Upstream version 2.11AA

pull/2/head
Stelios Bounanos 2008-05-10 00:12:17 +01:00
rodzic 34adb843b8
commit 7c2464d222
30 zmienionych plików z 2148 dodań i 517 usunięć

Wyświetl plik

@ -49,6 +49,28 @@ Change Log:
(waterfall drop). A lower latency gives better resolution in time
and less in frequency. The waterfall accuracy is still related to the
FFT size and that remains fixed for an accuracy of 1 Hz.
22) Added MultiPsk, DominoEX-FEC modes
23) Added new modem type DEX (Domino Extended), an FEC only Domino mode
that supports the full ASCII character set in the primary and the
printable ASCII English character set (less control codes) in the
secondary.
24) Use Fl_Preferences for the status
The new status filename is ~/.fldigi/status to avoid breaking older
versions.
25) Stacktrace updates - Some cosmetic changes to the output. Stack and
version info no longer printed twice when a signal is caught.
26) Use PortAudio extensions - Probes for PortAudio extensions with
dlopen. right now the only extension used is the one that changes the
JACK client name.
27) Updated PulseAudio code so that non-ppm resampling is performed by
PulseAudio when that sound i/o system is used.
28) Changed the capture resampling code for PortAudio and PulseAudio to
use libsamplerate's callback API.
29) Use fileselect filter values. Made the audio format independent of
the filename suffix in the generate/capture/playback code;
uses the fileselector filter value instead.
30) Update fileselector - Fileselector now remembers previous directory.
2.10.3)
1) Corrected memory leak bug.

Wyświetl plik

@ -9,7 +9,7 @@ dnl major and minor must be integers; patch may
dnl contain other characters or be empty
m4_define(FLDIGI_MAJOR, [2])
m4_define(FLDIGI_MINOR, [11])
m4_define(FLDIGI_PATCH, [Z])
m4_define(FLDIGI_PATCH, [AA])
AC_INIT([fldigi], FLDIGI_MAJOR.FLDIGI_MINOR[FLDIGI_PATCH], [w1hkj AT w1hkj DOT com])
@ -81,6 +81,10 @@ AC_FUNC_STRFTIME
AC_FUNC_STRTOD
AC_CHECK_FUNCS([getaddrinfo gethostbyname localtime_r memmove memset mkdir select snprintf socket strcasecmp strchr strdup strerror strncasecmp strcasestr strrchr strstr strtol uname vsnprintf])
# Check for dlopen
AC_SEARCH_LIBS([dlopen], [dl], [ac_cv_dlopen=1], [ac_cv_dlopen=0])
AC_DEFINE_UNQUOTED(HAVE_DLOPEN, $ac_cv_dlopen, [Define to 1 if we have dlopen])
AC_PRESERVE_HELP_ORDER

Wyświetl plik

@ -115,6 +115,8 @@ fldigi_SOURCES += \
dialogs/fl_digi.cxx \
dialogs/font_browser.cxx \
dialogs/Viewer.cxx \
dex/dex.cxx \
dex/dexvaricode.cxx \
dominoex/dominoex.cxx \
dominoex/dominovar.cxx \
feld/feld.cxx \
@ -146,6 +148,8 @@ fldigi_SOURCES += \
include/configuration.h \
include/cw.h \
include/digiscope.h \
include/dex.h \
include/dexvaricode.h \
include/dominoex.h \
include/dominovar.h \
include/feld.h \

636
src/dex/dex.cxx 100644
Wyświetl plik

@ -0,0 +1,636 @@
//
// dex.cxx -- dex modem
//
// Copyright (C) 2008
// David Freese (w1hkj@w1hkj.com)
//
// 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 <config.h>
#include <stdlib.h>
#include <iostream>
#include "confdialog.h"
#include "status.h"
#include "dex.h"
#include "trx.h"
#include "fft.h"
#include "filters.h"
#include "misc.h"
#include "sound.h"
#include "dexvaricode.h"
using namespace std;
char dexmsg[80];
void dex::tx_init(SoundBase *sc)
{
scard = sc;
txstate = TX_STATE_PREAMBLE;
txprevtone = 0;
bitstate = 0;
counter = 0;
txphase = 0;
videoText();
strSecXmtText = progdefaults.DEXsecText;
if (strSecXmtText.length() == 0)
strSecXmtText = "fldigi "PACKAGE_VERSION" ";
cptr = 0;
}
void dex::rx_init()
{
synccounter = 0;
symcounter = 0;
met1 = 0.0;
met2 = 0.0;
counter = 0;
phase[0] = 0.0;
for (int i = 0; i < DEXMAXFFTS; i++)
phase[i+1] = 0.0;
put_MODEstatus(mode);
put_sec_char(0);
syncfilter->reset();
datashreg = 1;
}
void dex::reset_filters()
{
// fft filter at first IF frequency
if (progdefaults.DEX_FILTER == false) {
fft->create_filter( (DEXFIRSTIF - 2.0 * bandwidth) / samplerate,
(DEXFIRSTIF + 2.0 * bandwidth)/ samplerate );
} else {
fft->create_filter( (DEXFIRSTIF - 0.5 * progdefaults.DEX_BW * bandwidth) / samplerate,
(DEXFIRSTIF + 0.5 * progdefaults.DEX_BW * bandwidth)/ samplerate );
}
filter_reset = false;
}
void dex::restart()
{
filter_reset = true;
}
void dex::init()
{
modem::init();
reset_filters();
rx_init();
set_scope_mode(Digiscope::DOMDATA);
}
dex::~dex()
{
if (hilbert) delete hilbert;
for (int i = 0; i < DEXMAXFFTS; i++) {
if (binsfft[i]) delete binsfft[i];
}
for (int i = 0; i < DEXSCOPESIZE; i++) {
if (vidfilter[i]) delete vidfilter[i];
}
if (syncfilter) delete syncfilter;
if (pipe) delete [] pipe;
if (fft) delete fft;
if (Rxinlv) delete Rxinlv;
if (Txinlv) delete Txinlv;
if (Dec) delete Dec;
if (Enc) delete Enc;
}
dex::dex(trx_mode md)
{
int basetone, lotone, hitone;
mode = md;
switch (mode) {
// 11.025 kHz modes
case MODE_DEX5:
symlen = 2048;
doublespaced = 1;
samplerate = 11025;
break;
case MODE_DEX11:
symlen = 1024;
doublespaced = 0;
samplerate = 11025;
break;
case MODE_DEX22:
symlen = 512;
doublespaced = 0;
samplerate = 11025;
break;
// 8kHz modes
case MODE_DEX4:
symlen = 2048;
doublespaced = 1;
samplerate = 8000;
break;
case MODE_DEX8:
symlen = 1024;
doublespaced = 1;
samplerate = 8000;
case MODE_DEX16:
default:
symlen = 512;
doublespaced = 0;
samplerate = 8000;
break;
}
basetone = (int)floor(DEXBASEFREQ * symlen / samplerate + 0.5);
lotone = basetone - (DEXNUMMTONES/2) * (doublespaced ? 2 : 1);
hitone = basetone + 3 * (DEXNUMMTONES/2) * (doublespaced ? 2 : 1);
tonespacing = (double) (samplerate * ((doublespaced) ? 2 : 1)) / symlen;
bandwidth = DEXNUMMTONES * tonespacing;
hilbert = new C_FIR_filter();
hilbert->init_hilbert(37, 1);
paths = progdefaults.DEX_PATHS;
for (int i = 0; i < DEXMAXFFTS; i++)
binsfft[i] = new sfft (symlen, lotone, hitone);
// fft filter at first if frequency
fft = new fftfilt( (DEXFIRSTIF - 0.5 * progdefaults.DEX_BW * bandwidth) / samplerate,
(DEXFIRSTIF + 0.5 * progdefaults.DEX_BW * bandwidth)/ samplerate,
1024 );
for (int i = 0; i < DEXSCOPESIZE; i++)
vidfilter[i] = new Cmovavg(16);
syncfilter = new Cmovavg(8);
twosym = 2 * symlen;
pipe = new DEXrxpipe[twosym];
scopedata.alloc(DEXSCOPESIZE);
videodata.alloc((DEXMAXFFTS * DEXNUMMTONES * 2 * (doublespaced?2:1) ));
pipeptr = 0;
symcounter = 0;
metric = 0.0;
fragmentsize = symlen;
s2n = 0.0;
prev1symbol = prev2symbol = 0;
Enc = new encoder (DEX_K, DEX_POLY1, DEX_POLY2);
Dec = new viterbi (DEX_K, DEX_POLY1, DEX_POLY2);
Dec->settraceback (45);
Dec->setchunksize (1);
Txinlv = new interleave (4, INTERLEAVE_FWD); // 4x4x10
Rxinlv = new interleave (4, INTERLEAVE_REV); // 4x4x10
bitstate = 0;
symbolpair[0] = symbolpair[1] = 0;
datashreg = 1;
init();
}
//=====================================================================
// rx modules
complex dex::mixer(int n, complex in)
{
complex z;
double f;
// first IF mixer (n == 0) plus
// DEXMAXFFTS mixers are supported each separated by 1/DEXMAXFFTS bin size
// n == 1, 2, 3, 4 ... DEXMAXFFTS
if (n == 0)
f = frequency - DEXFIRSTIF;
else
f = DEXFIRSTIF - DEXBASEFREQ - bandwidth/2 + (samplerate / symlen) * (1.0 * n / paths );
z.re = cos(phase[n]);
z.im = sin(phase[n]);
z = z * in;
phase[n] -= twopi * f / samplerate;
if (phase[n] > M_PI)
phase[n] -= twopi;
else if (phase[n] < M_PI)
phase[n] += twopi;
return z;
}
void dex::recvchar(int c)
{
if (c == -1)
return;
if (c & 0x100)
put_sec_char(c & 0xFF);
else
put_rx_char(c & 0xFF);
}
//=============================================================================
// Receive
//=============================================================================
void dex::decodePairs(unsigned char symbol)
{
int c, ch, met;
symbolpair[0] = symbolpair[1];
symbolpair[1] = symbol;
symcounter = symcounter ? 0 : 1;
if (symcounter) return;
c = Dec->decode (symbolpair, &met);
if (c == -1)
return;
if (progStatus.sqlonoff && metric < progStatus.sldrSquelchValue)
return;
datashreg = (datashreg << 1) | !!c;
if ((datashreg & 7) == 1) {
ch = dexvaridec(datashreg >> 1);
recvchar(ch);
datashreg = 1;
}
}
void dex::decodeEX(int ch)
{
unsigned char symbols[4];
int c = ch;
for (int i = 0; i < 4; i++) {
if (c & 1 == 1) symbols[3-i] = 255;
else symbols[3-i] = 1;
c = c / 2;
}
Rxinlv->symbols(symbols);
for (int i = 0; i < 4; i++) decodePairs(symbols[i]);
}
void dex::decodesymbol()
{
int c;
double fdiff;
// Decode the IFK+ sequence, which results in a single nibble
fdiff = currsymbol - prev1symbol;
if (reverse) fdiff = -fdiff;
if (doublespaced) fdiff /= 2 * paths;
else fdiff /= paths;
c = (int)floor(fdiff + .5) - 2;
if (c < 0) c += DEXNUMMTONES;
decodeEX(c);
}
int dex::harddecode()
{
double x, max = 0.0;
int symbol = 0;
for (int i = 0; i < (paths * DEXNUMMTONES * 2 * (doublespaced ? 2 : 1) ); i++) {
x = pipe[pipeptr].vector[i].mag();
if (x > max) {
max = x;
symbol = i;
}
}
return symbol;
}
void dex::update_syncscope()
{
double max = 0, min = 1e6, range, mag;
// dom waterfall
memset(videodata, 0, (paths * DEXNUMMTONES * 2 * (doublespaced?2:1) ) * sizeof(double));
if (!progStatus.sqlonoff || metric >= progStatus.sldrSquelchValue) {
for (int i = 0; i < (paths * DEXNUMMTONES * 2 * (doublespaced?2:1) ); i++ ) {
mag = pipe[pipeptr].vector[i].mag();
if (max < mag) max = mag;
if (min > mag) min = mag;
}
range = max - min;
for (int i = 0; i < (paths * DEXNUMMTONES * 2 * (doublespaced?2:1) ); i++ ) {
if (range > 2) {
mag = (pipe[pipeptr].vector[i].mag() - min) / range + 0.0001;
mag = 1 + 2 * log10(mag);
if (mag < 0) mag = 0;
} else
mag = 0;
videodata[i] = 255*mag;
}
}
set_video(videodata, (paths * DEXNUMMTONES * 2 * (doublespaced?2:1) ), false);
videodata.next();
// set_scope(scopedata, twosym);
// 64 data points is sufficient to show the signal progression through the
// convolution filter.
memset(scopedata, 0, DEXSCOPESIZE * sizeof(double));
if (!progStatus.sqlonoff || metric >= progStatus.sldrSquelchValue) {
for (unsigned int i = 0, j = 0; i < DEXSCOPESIZE; i++) {
j = (pipeptr + i * twosym / DEXSCOPESIZE + 1) % (twosym);
scopedata[i] = vidfilter[i]->run(pipe[j].vector[prev1symbol].mag());
}
}
set_scope(scopedata, DEXSCOPESIZE);
scopedata.next();
}
void dex::synchronize()
{
// int syn = -1;
double syn = -1;
double val, max = 0.0;
if (currsymbol == prev1symbol)
return;
if (prev1symbol == prev2symbol)
return;
for (unsigned int i = 0, j = pipeptr; i < twosym; i++) {
val = (pipe[j].vector[prev1symbol]).mag();
if (val > max) {
max = val;
syn = i;
}
j = (j + 1) % twosym;
}
syn = syncfilter->run(syn);
synccounter += (int) floor(1.0 * (syn - symlen) / DEXNUMMTONES + 0.5);
}
void dex::eval_s2n()
{
if (currsymbol != prev1symbol && prev1symbol != prev2symbol) {
sig = pipe[pipeptr].vector[currsymbol].mag();
noise = 0.0;
for (int i = 0; i < paths * DEXNUMMTONES * 2 * (doublespaced?2:1); i++) {
if (i != currsymbol)
noise += pipe[pipeptr].vector[i].mag();
}
noise /= (paths * DEXNUMMTONES * 2 * (doublespaced?2:1) - 1);
s2n = decayavg( s2n, sig / noise, 8);
metric = 3*(20*log10(s2n) - 9.0);
display_metric(metric);
snprintf(dexmsg, sizeof(dexmsg), "s/n %3.0f dB", metric / 3.0 - 2.0);
put_Status1(dexmsg);
}
}
int dex::rx_process(const double *buf, int len)
{
complex zref, z, *zp, *bins = 0;
int n;
if (filter_reset) reset_filters();
if (paths != progdefaults.DEX_PATHS) {
paths = progdefaults.DEX_PATHS;
reset_filters();
}
while (len) {
// create analytic signal at first IF
zref.re = zref.im = *buf++;
hilbert->run(zref, zref);
zref = mixer(0, zref);
// filter using fft convolution
n = fft->run(zref, &zp);
if (n) {
for (int i = 0; i < n; i++) {
// process DEXMAXFFTS sets of sliding FFTs spaced at 1/DEXMAXFFTS bin intervals each of which
// is a matched filter for the current symbol length
for (int n = 0; n < paths; n++) {
// shift in frequency to base band for the sliding DFTs
z = mixer(n + 1, zp[i]);
bins = binsfft[n]->run(z);
// copy current vector to the pipe interleaving the FFT vectors
for (int i = 0; i < DEXNUMMTONES * 2 * (doublespaced ? 2 : 1); i++) {
pipe[pipeptr].vector[n + paths * i] = bins[i];
}
}
if (--synccounter <= 0) {
synccounter = symlen;
currsymbol = harddecode();
decodesymbol();
synchronize();
update_syncscope();
eval_s2n();
prev2symbol = prev1symbol;
prev1symbol = currsymbol;
}
pipeptr++;
if (pipeptr >= twosym)
pipeptr = 0;
}
}
--len;
}
return 0;
}
//=============================================================================
// Transmit methods
//=============================================================================
int dex::get_secondary_char()
{
char chr;
if (cptr > strSecXmtText.length()) cptr = 0;
chr = strSecXmtText[cptr++];
put_sec_char( chr );
return chr;
}
void dex::sendtone(int tone, int duration)
{
double f, phaseincr;
f = tone * tonespacing + get_txfreq_woffset() - bandwidth / 2;
phaseincr = twopi * f / samplerate;
for (int j = 0; j < duration; j++) {
for (int i = 0; i < symlen; i++) {
outbuf[i] = cos(txphase);
txphase -= phaseincr;
if (txphase > M_PI)
txphase -= twopi;
else if (txphase < M_PI)
txphase += twopi;
}
ModulateXmtr(outbuf, symlen);
}
}
void dex::sendsymbol(int sym)
{
complex z;
int tone;
tone = (txprevtone + 2 + sym) % DEXNUMMTONES;
txprevtone = tone;
if (reverse)
tone = (DEXNUMMTONES - 1) - tone;
sendtone(tone, 1);
}
// Send DEX FEC varicode
void dex::sendchar(unsigned char c, int secondary)
{
const char *code;
code = dexvarienc(c, secondary);
while (*code) {
int data = Enc->encode(*code++ - '0');
for (int i = 0; i < 2; i++) {
bitshreg = (bitshreg << 1) | ((data >> i) & 1);
bitstate++;
if (bitstate == 4) {
Txinlv->bits(&bitshreg);
sendsymbol(bitshreg);
bitstate = 0;
bitshreg = 0;
}
}
}
if (!secondary)
put_echo_char(c);
}
void dex::sendidle()
{
sendchar(0, 0); // <NUL>
}
void dex::sendsecondary()
{
int c = get_secondary_char();
sendchar(c & 0xFF, 1);
}
void dex::Clearbits()
{
int data = Enc->encode(0);
for (int k = 0; k < 100; k++) {
for (int i = 0; i < 2; i++) {
bitshreg = (bitshreg << 1) | ((data >> i) & 1);
bitstate++;
if (bitstate == 4) {
Txinlv->bits(&bitshreg);
bitstate = 0;
bitshreg = 0;
}
}
}
}
void dex::flushtx()
{
// flush the varicode decoder at the other end
// flush the convolutional encoder and interleaver
for (int i = 0; i < 4; i++)
sendidle();
bitstate = 0;
}
int dex::tx_process()
{
int i;
switch (txstate) {
case TX_STATE_PREAMBLE:
Clearbits();
for (int j = 0; j < 16; j++) sendsymbol(0);
// sendtone(DEXNUMMTONES/2, 4);
// for (int k = 0; k < 3; k++) {
// sendtone(DEXNUMMTONES, 3);
// sendtone(0, 3);
// }
// sendtone(DEXNUMMTONES/2, 4);
sendidle();
txstate = TX_STATE_START;
break;
case TX_STATE_START:
sendchar('\r', 0);
sendchar(2, 0); // STX
sendchar('\r', 0);
txstate = TX_STATE_DATA;
break;
case TX_STATE_DATA:
i = get_tx_char();
if (i == -1)
sendsecondary();
else if (i == 3)
txstate = TX_STATE_END;
else
sendchar(i, 0);
if (stopflag)
txstate = TX_STATE_END;
break;
case TX_STATE_END:
sendchar('\r', 0);
sendchar(4, 0); // EOT
sendchar('\r', 0);
txstate = TX_STATE_FLUSH;
break;
case TX_STATE_FLUSH:
flushtx();
cwid();
return -1;
}
return 0;
}

Wyświetl plik

@ -0,0 +1,194 @@
// ----------------------------------------------------------------------------
//
// dexvaricode.cxx -- DEX Varicode
//
// Copyright (C) 2009
// Dave Freese, W1HKJ
//
// This file is part of fldigi.
//
// 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 <config.h>
#include "mfskvaricode.h"
#include "dexvaricode.h"
// DEX varicode is an extended set of the IZ8BLY MFSK varicode that uses the
// unallocated remaining 12 bit codes for a secondary character set.
// Primary character set (same as MFSK)
// extended 12 bit codes for secondary characters
// 90 used, leaving 10 for possible special use
// encoding table
static const char *dex_varicode[] = {
"101110000000", /* 032 - <SPC> */
"101110100000", /* 033 - ! */
"101110101000", /* 034 - '"' */
"101110101100", /* 035 - # */
"101110110000", /* 036 - $ */
"101110110100", /* 037 - % */
"101110111000", /* 038 - & */
"101110111100", /* 039 - ' */
"101111000000", /* 040 - ( */
"101111010000", /* 041 - ) */
"101111010100", /* 042 - * */
"101111011000", /* 043 - + */
"101111011100", /* 044 - , */
"101111100000", /* 045 - - */
"101111101000", /* 046 - . */
"101111101100", /* 047 - / */
"101111110000", /* 048 - 0 */
"101111110100", /* 049 - 1 */
"101111111000", /* 050 - 2 */
"101111111100", /* 051 - 3 */
"110000000000", /* 052 - 4 */
"110100000000", /* 053 - 5 */
"110101000000", /* 054 - 6 */
"110101010100", /* 055 - 7 */
"110101011000", /* 056 - 8 */
"110101011100", /* 057 - 9 */
"110101100000", /* 058 - : */
"110101101000", /* 059 - ; */
"110101101100", /* 060 - < */
"110101110000", /* 061 - = */
"110101110100", /* 062 - > */
"110101111000", /* 063 - ? */
"110101111100", /* 064 - @ */
"110110000000", /* 065 - A */
"110110100000", /* 066 - B */
"110110101000", /* 067 - C */
"110110101100", /* 068 - D */
"110110110000", /* 069 - E */
"110110110100", /* 070 - F */
"110110111000", /* 071 - G */
"110110111100", /* 072 - H */
"110111000000", /* 073 - I */
"110111010000", /* 074 - J */
"110111010100", /* 075 - K */
"110111011000", /* 076 - L */
"110111011100", /* 077 - M */
"110111100000", /* 078 - N */
"110111101000", /* 079 - O */
"110111101100", /* 080 - P */
"110111110000", /* 081 - Q */
"110111110100", /* 082 - R */
"110111111000", /* 083 - S */
"110111111100", /* 084 - T */
"111000000000", /* 085 - U */
"111010000000", /* 086 - V */
"111010100000", /* 087 - W */
"111010101100", /* 088 - X */
"111010110000", /* 089 - Y */
"111010110100", /* 090 - Z */
"111010111000", /* 091 - [ */
"111010111100", /* 092 - \ */
"111011000000", /* 093 - ] */
"111011010000", /* 094 - ^ */
"111011010100", /* 095 - _ */
"111011011000", /* 096 - ` */
"111011011100", /* 097 - a */
"111011100000", /* 098 - b */
"111011101000", /* 099 - c */
"111011101100", /* 100 - d */
"111011110000", /* 101 - e */
"111011110100", /* 102 - f */
"111011111000", /* 103 - g */
"111011111100", /* 104 - h */
"111100000000", /* 105 - i */
"111101000000", /* 106 - j */
"111101010000", /* 107 - k */
"111101010100", /* 108 - l */
"111101011000", /* 109 - m */
"111101011100", /* 110 - n */
"111101100000", /* 111 - o */
"111101101000", /* 112 - p */
"111101101100", /* 113 - q */
"111101110000", /* 114 - r */
"111101110100", /* 115 - s */
"111101111000", /* 116 - t */
"111101111100", /* 117 - u */
"111110000000", /* 118 - v */
"111110100000", /* 119 - w */
"111110101000", /* 120 - x */
"111110101100", /* 121 - y */
"111110110000" /* 122 - z */
};
// unused 12 bit varicodes
/*
static char *unused[] = {
"111110110100",
"111110111000",
"111110111100",
"111111000000",
"111111010100",
"111111011000",
"111111011100",
"111111100000",
"111111101000",
"111111101100",
"111111110000",
"111111110100",
"111111111100"
};
*/
// decoding table
static const unsigned int dex_varidecode[] = {
0xB80, 0xBA0, 0xBA8, 0xBAC, 0xBB0, 0xBB4, 0xBB8, 0xBBC,
0xBC0, 0xBD0, 0xBD4, 0xBD8, 0xBDC, 0xBE0, 0xBE8, 0xBEC,
0xBF0, 0xBF4, 0xBF8, 0xBFC, 0xC00, 0xD00, 0xD40, 0xD54,
0xD58, 0xD5C, 0xD60, 0xD68, 0xD6C, 0xD70, 0xD74, 0xD78,
0xD7C, 0xD80, 0xDA0, 0xDA8, 0xDAC, 0xDB0, 0xDB4, 0xDB8,
0xDBC, 0xDC0, 0xDD0, 0xDD4, 0xDD8, 0xDDC, 0xDE0, 0xDE8,
0xDEC, 0xDF0, 0xDF4, 0xDF8, 0xDFC, 0xE00, 0xE80, 0xEA0,
0xEAC, 0xEB0, 0xEB4, 0xEB8, 0xEBC, 0xEC0, 0xED0, 0xED4,
0xED8, 0xEDC, 0xEE0, 0xEE8, 0xEEC, 0xEF0, 0xEF4, 0xEF8,
0xEFC, 0xF00, 0xF40, 0xF50, 0xF54, 0xF58, 0xF5C, 0xF60,
0xF68, 0xF6C, 0xF70, 0xF74, 0xF78, 0xF7C, 0xF80, 0xFA0,
0xFA8, 0xFAC, 0xFB0
};
const char *dexvarienc(int c, int sec)
{
if (sec == 0)
return varienc(c); // mfsk varicode
else
if (c >= ' ' && c <= 'z')
return dex_varicode[c - ' '];
return varienc(0); // return code for NULL if not in tables
}
int dexvaridec(unsigned int symbol)
{
int i;
if (symbol < 0xB80)
return varidec(symbol); // find in the MFSK decode table
for (i = 0; i < 92; i++)
if (symbol == dex_varidecode[i])
return (' ' + i + 0x100); // found in the extended decode table
return -1; // not found
}

Wyświetl plik

@ -884,6 +884,38 @@ static void cb_cntPostTiming(Fl_Counter* o, void*) {
progdefaults.changed = true;
}
Fl_Group *tabDEX=(Fl_Group *)0;
Fl_Input *txtDEXSecondary=(Fl_Input *)0;
static void cb_txtDEXSecondary(Fl_Input* o, void*) {
progdefaults.DEXsecText = o->value();
progdefaults.changed = true;
}
Fl_Counter *valDEX_BW=(Fl_Counter *)0;
static void cb_valDEX_BW(Fl_Counter* o, void*) {
progdefaults.DEX_BW = o->value();
resetDEX();
progdefaults.changed = true;
}
Fl_Check_Button *valDEX_FILTER=(Fl_Check_Button *)0;
static void cb_valDEX_FILTER(Fl_Check_Button* o, void*) {
progdefaults.DEX_FILTER = o->value();
resetDEX();
progdefaults.changed = true;
}
Fl_Counter *valDEX_PATHS=(Fl_Counter *)0;
static void cb_valDEX_PATHS(Fl_Counter* o, void*) {
progdefaults.DEX_PATHS = (int)o->value();
progdefaults.changed = true;
}
Fl_Group *tabDomEX=(Fl_Group *)0;
Fl_Input *txtSecondary=(Fl_Input *)0;
@ -893,13 +925,6 @@ static void cb_txtSecondary(Fl_Input* o, void*) {
progdefaults.changed = true;
}
Fl_Button *btnRestartDomEX=(Fl_Button *)0;
static void cb_btnRestartDomEX(Fl_Button*, void*) {
progdefaults.storeDefaults();
resetDOMEX();
}
Fl_Counter *valDominoEX_BW=(Fl_Counter *)0;
static void cb_valDominoEX_BW(Fl_Counter* o, void*) {
@ -916,6 +941,20 @@ resetDOMEX();
progdefaults.changed = true;
}
Fl_Check_Button *chkDominoEX_FEC=(Fl_Check_Button *)0;
static void cb_chkDominoEX_FEC(Fl_Check_Button* o, void*) {
progdefaults.DOMINOEX_FEC = o->value();
progdefaults.changed = true;
}
Fl_Counter *valDominoEX_PATHS=(Fl_Counter *)0;
static void cb_valDominoEX_PATHS(Fl_Counter* o, void*) {
progdefaults.DOMINOEX_PATHS = (int)o->value();
progdefaults.changed = true;
}
Fl_Group *tabFeld=(Fl_Group *)0;
Fl_Choice *selHellFont=(Fl_Choice *)0;
@ -2053,33 +2092,80 @@ l with your sound hardware.");
} // Fl_Counter* cntPostTiming
tabCWQSK->end();
} // Fl_Group* tabCWQSK
{ tabDomEX = new Fl_Group(0, 50, 400, 170, "DomEX");
{ tabDEX = new Fl_Group(0, 44, 400, 170, "Dex");
tabDEX->color((Fl_Color)51);
tabDEX->selection_color((Fl_Color)51);
{ txtDEXSecondary = new Fl_Input(20, 75, 360, 44, "Secondary Text");
txtDEXSecondary->type(4);
txtDEXSecondary->callback((Fl_Callback*)cb_txtDEXSecondary);
txtDEXSecondary->align(FL_ALIGN_TOP_LEFT);
txtDEXSecondary->when(FL_WHEN_CHANGED);
} // Fl_Input* txtDEXSecondary
{ Fl_Counter* o = valDEX_BW = new Fl_Counter(20, 130, 63, 21, "BW factor:");
valDEX_BW->type(1);
valDEX_BW->minimum(1);
valDEX_BW->maximum(2);
valDEX_BW->step(0.1);
valDEX_BW->value(1.5);
valDEX_BW->callback((Fl_Callback*)cb_valDEX_BW);
o->value(progdefaults.DEX_BW);
} // Fl_Counter* valDEX_BW
{ Fl_Check_Button* o = valDEX_FILTER = new Fl_Check_Button(110, 130, 83, 19, "Filter ON");
valDEX_FILTER->down_box(FL_DOWN_BOX);
valDEX_FILTER->value(1);
valDEX_FILTER->callback((Fl_Callback*)cb_valDEX_FILTER);
o->value(progdefaults.DEX_FILTER);
} // Fl_Check_Button* valDEX_FILTER
{ Fl_Counter* o = valDEX_PATHS = new Fl_Counter(20, 174, 63, 21, "Paths");
valDEX_PATHS->type(1);
valDEX_PATHS->minimum(4);
valDEX_PATHS->maximum(8);
valDEX_PATHS->step(1);
valDEX_PATHS->value(5);
valDEX_PATHS->callback((Fl_Callback*)cb_valDEX_PATHS);
o->value(progdefaults.DEX_PATHS);
} // Fl_Counter* valDEX_PATHS
tabDEX->end();
} // Fl_Group* tabDEX
{ tabDomEX = new Fl_Group(0, 50, 400, 170, "Dom");
tabDomEX->color((Fl_Color)51);
tabDomEX->selection_color((Fl_Color)51);
tabDomEX->hide();
{ txtSecondary = new Fl_Input(20, 75, 360, 44, "Secondary Text");
txtSecondary->type(4);
txtSecondary->callback((Fl_Callback*)cb_txtSecondary);
txtSecondary->align(FL_ALIGN_TOP_LEFT);
txtSecondary->when(FL_WHEN_CHANGED);
} // Fl_Input* txtSecondary
{ btnRestartDomEX = new Fl_Button(300, 172, 79, 28, "Restart");
btnRestartDomEX->callback((Fl_Callback*)cb_btnRestartDomEX);
btnRestartDomEX->hide();
} // Fl_Button* btnRestartDomEX
{ Fl_Counter* o = valDominoEX_BW = new Fl_Counter(25, 134, 63, 21, "BW factor:");
{ Fl_Counter* o = valDominoEX_BW = new Fl_Counter(20, 130, 63, 21, "BW factor:");
valDominoEX_BW->type(1);
valDominoEX_BW->minimum(1);
valDominoEX_BW->maximum(2);
valDominoEX_BW->step(0.1);
valDominoEX_BW->value(2);
valDominoEX_BW->value(1.5);
valDominoEX_BW->callback((Fl_Callback*)cb_valDominoEX_BW);
o->value(progdefaults.DOMINOEX_BW);
} // Fl_Counter* valDominoEX_BW
{ Fl_Check_Button* o = valDominoEX_FILTER = new Fl_Check_Button(107, 136, 83, 19, "Filter ON");
{ Fl_Check_Button* o = valDominoEX_FILTER = new Fl_Check_Button(110, 130, 83, 19, "Filter ON");
valDominoEX_FILTER->down_box(FL_DOWN_BOX);
valDominoEX_FILTER->value(1);
valDominoEX_FILTER->callback((Fl_Callback*)cb_valDominoEX_FILTER);
o->value(progdefaults.DOMINOEX_FILTER);
} // Fl_Check_Button* valDominoEX_FILTER
{ Fl_Check_Button* o = chkDominoEX_FEC = new Fl_Check_Button(220, 130, 70, 15, "FEC");
chkDominoEX_FEC->down_box(FL_DOWN_BOX);
chkDominoEX_FEC->callback((Fl_Callback*)cb_chkDominoEX_FEC);
o->value(progdefaults.DOMINOEX_FEC);
} // Fl_Check_Button* chkDominoEX_FEC
{ Fl_Counter* o = valDominoEX_PATHS = new Fl_Counter(20, 174, 63, 21, "Paths");
valDominoEX_PATHS->type(1);
valDominoEX_PATHS->minimum(4);
valDominoEX_PATHS->maximum(8);
valDominoEX_PATHS->step(1);
valDominoEX_PATHS->value(5);
valDominoEX_PATHS->callback((Fl_Callback*)cb_valDominoEX_PATHS);
o->value(progdefaults.DOMINOEX_PATHS);
} // Fl_Counter* valDominoEX_PATHS
tabDomEX->end();
} // Fl_Group* tabDomEX
{ tabFeld = new Fl_Group(0, 50, 400, 170, "Feld");

Wyświetl plik

@ -1052,9 +1052,43 @@ progdefaults.changed = true;}
code1 {o->maximum((int)(2400/progdefaults.CWspeed)/2.0);}
}
}
Fl_Group tabDEX {
label Dex open
xywh {0 44 400 170} color 51 selection_color 51
} {
Fl_Input txtDEXSecondary {
label {Secondary Text}
callback {progdefaults.DEXsecText = o->value();
progdefaults.changed = true;}
xywh {20 75 360 44} type Multiline align 5 when 1
}
Fl_Counter valDEX_BW {
label {BW factor:}
callback {progdefaults.DEX_BW = o->value();
resetDEX();
progdefaults.changed = true;}
xywh {20 130 63 21} type Simple minimum 1 maximum 2 step 0.1 value 1.5
code0 {o->value(progdefaults.DEX_BW);}
}
Fl_Check_Button valDEX_FILTER {
label {Filter ON}
callback {progdefaults.DEX_FILTER = o->value();
resetDEX();
progdefaults.changed = true;}
xywh {110 130 83 19} down_box DOWN_BOX value 1
code0 {o->value(progdefaults.DEX_FILTER);}
}
Fl_Counter valDEX_PATHS {
label Paths
callback {progdefaults.DEX_PATHS = (int)o->value();
progdefaults.changed = true;} selected
xywh {20 174 63 21} type Simple minimum 4 maximum 8 step 1 value 5
code0 {o->value(progdefaults.DEX_PATHS);}
}
}
Fl_Group tabDomEX {
label DomEX open
xywh {0 50 400 170} color 51 selection_color 51
label Dom open
xywh {0 50 400 170} color 51 selection_color 51 hide
} {
Fl_Input txtSecondary {
label {Secondary Text}
@ -1062,28 +1096,36 @@ progdefaults.changed = true;}
progdefaults.changed = true;}
xywh {20 75 360 44} type Multiline align 5 when 1
}
Fl_Button btnRestartDomEX {
label Restart
callback {progdefaults.storeDefaults();
resetDOMEX();}
xywh {300 172 79 28} hide
}
Fl_Counter valDominoEX_BW {
label {BW factor:}
callback {progdefaults.DOMINOEX_BW = o->value();
resetDOMEX();
progdefaults.changed = true;}
xywh {25 134 63 21} type Simple minimum 1 maximum 2 step 0.1 value 2
xywh {20 130 63 21} type Simple minimum 1 maximum 2 step 0.1 value 1.5
code0 {o->value(progdefaults.DOMINOEX_BW);}
}
Fl_Check_Button valDominoEX_FILTER {
label {Filter ON}
callback {progdefaults.DOMINOEX_FILTER = o->value();
resetDOMEX();
progdefaults.changed = true;} selected
xywh {107 136 83 19} down_box DOWN_BOX
progdefaults.changed = true;}
xywh {110 130 83 19} down_box DOWN_BOX value 1
code0 {o->value(progdefaults.DOMINOEX_FILTER);}
}
Fl_Check_Button chkDominoEX_FEC {
label FEC
callback {progdefaults.DOMINOEX_FEC = o->value();
progdefaults.changed = true;}
xywh {220 130 70 15} down_box DOWN_BOX
code0 {o->value(progdefaults.DOMINOEX_FEC);}
}
Fl_Counter valDominoEX_PATHS {
label Paths
callback {progdefaults.DOMINOEX_PATHS = (int)o->value();
progdefaults.changed = true;}
xywh {20 174 63 21} type Simple minimum 4 maximum 8 step 1 value 5
code0 {o->value(progdefaults.DOMINOEX_PATHS);}
}
}
Fl_Group tabFeld {
label Feld open

Wyświetl plik

@ -65,6 +65,7 @@
#include "mt63.h"
#include "rtty.h"
#include "olivia.h"
#include "dex.h"
#include "dominoex.h"
#include "feld.h"
#include "throb.h"
@ -201,6 +202,16 @@ Fl_Menu_Item quick_change_mt63[] = {
{ 0 }
};
Fl_Menu_Item quick_change_dex[] = {
{ mode_info[MODE_DEX4].name, 0, cb_init_mode, (void *)MODE_DEX4 },
{ mode_info[MODE_DEX5].name, 0, cb_init_mode, (void *)MODE_DEX5 },
{ mode_info[MODE_DEX8].name, 0, cb_init_mode, (void *)MODE_DEX8 },
{ mode_info[MODE_DEX11].name, 0, cb_init_mode, (void *)MODE_DEX11 },
{ mode_info[MODE_DEX16].name, 0, cb_init_mode, (void *)MODE_DEX16 },
{ mode_info[MODE_DEX22].name, 0, cb_init_mode, (void *)MODE_DEX22 },
{ 0 }
};
Fl_Menu_Item quick_change_domino[] = {
{ mode_info[MODE_DOMINOEX4].name, 0, cb_init_mode, (void *)MODE_DOMINOEX4 },
{ mode_info[MODE_DOMINOEX5].name, 0, cb_init_mode, (void *)MODE_DOMINOEX5 },
@ -390,6 +401,14 @@ void init_modem(trx_mode mode)
modem_config_tab = tabCW;
break;
case MODE_DEX4: case MODE_DEX5: case MODE_DEX8:
case MODE_DEX11: case MODE_DEX16: case MODE_DEX22:
startup_modem(*mode_info[mode].modem ? *mode_info[mode].modem :
*mode_info[mode].modem = new dex(mode));
quick_change = quick_change_dex;
modem_config_tab = tabDEX;
break;
case MODE_DOMINOEX4: case MODE_DOMINOEX5: case MODE_DOMINOEX8:
case MODE_DOMINOEX11: case MODE_DOMINOEX16: case MODE_DOMINOEX22:
startup_modem(*mode_info[mode].modem ? *mode_info[mode].modem :
@ -472,7 +491,7 @@ void init_modem(trx_mode mode)
}
clear_StatusMessages();
progStatus.saveModeState(mode);
progStatus.lastmode = mode;
}
void init_modem_sync(trx_mode m)
@ -1020,6 +1039,15 @@ Fl_Menu_Item menu_[] = {
{ mode_info[MODE_CW].name, 0, cb_init_mode, (void *)MODE_CW, 0, FL_NORMAL_LABEL, 0, 14, 0},
{"DEX", 0, 0, 0, FL_SUBMENU, FL_NORMAL_LABEL, 0, 14, 0},
{ mode_info[MODE_DEX4].name, 0, cb_init_mode, (void *)MODE_DEX4, 0, FL_NORMAL_LABEL, 0, 14, 0},
{ mode_info[MODE_DEX5].name, 0, cb_init_mode, (void *)MODE_DEX5, 0, FL_NORMAL_LABEL, 0, 14, 0},
{ mode_info[MODE_DEX8].name, 0, cb_init_mode, (void *)MODE_DEX8, 0, FL_NORMAL_LABEL, 0, 14, 0},
{ mode_info[MODE_DEX11].name, 0, cb_init_mode, (void *)MODE_DEX11, 0, FL_NORMAL_LABEL, 0, 14, 0},
{ mode_info[MODE_DEX16].name, 0, cb_init_mode, (void *)MODE_DEX16, 0, FL_NORMAL_LABEL, 0, 14, 0},
{ mode_info[MODE_DEX22].name, 0, cb_init_mode, (void *)MODE_DEX22, 0, FL_NORMAL_LABEL, 0, 14, 0},
{0,0,0,0,0,0,0,0,0},
{"DominoEX", 0, 0, 0, FL_SUBMENU, FL_NORMAL_LABEL, 0, 14, 0},
{ mode_info[MODE_DOMINOEX4].name, 0, cb_init_mode, (void *)MODE_DOMINOEX4, 0, FL_NORMAL_LABEL, 0, 14, 0},
{ mode_info[MODE_DOMINOEX5].name, 0, cb_init_mode, (void *)MODE_DOMINOEX5, 0, FL_NORMAL_LABEL, 0, 14, 0},
@ -1749,7 +1777,7 @@ void clear_status_cb(void *)
void put_status(const char *msg, double timeout)
{
static char m[60];
static char m[50];
strncpy(m, msg, sizeof(m));
m[sizeof(m) - 1] = '\0';
@ -1927,6 +1955,18 @@ void resetOLIVIA() {
active_modem->restart();
}
void resetDEX() {
trx_mode md = active_modem->get_mode();
if (md == MODE_DEX4 ||
md == MODE_DEX5 ||
md == MODE_DEX8 ||
md == MODE_DEX11 ||
md == MODE_DEX16 ||
md == MODE_DEX22 ) {
active_modem->restart();
}
}
void resetDOMEX() {
trx_mode md = active_modem->get_mode();
if (md == MODE_DOMINOEX4 ||
@ -1935,8 +1975,6 @@ void resetDOMEX() {
md == MODE_DOMINOEX11 ||
md == MODE_DOMINOEX16 ||
md == MODE_DOMINOEX22 ) {
// trx_reset();
active_modem->restart();
}
}

Wyświetl plik

@ -36,6 +36,7 @@
#include "filters.h"
#include "misc.h"
#include "sound.h"
#include "mfskvaricode.h"
using namespace std;
@ -46,6 +47,7 @@ void dominoex::tx_init(SoundBase *sc)
scard = sc;
txstate = TX_STATE_PREAMBLE;
txprevtone = 0;
bitstate = 0;
counter = 0;
txphase = 0;
videoText();
@ -59,10 +61,13 @@ void dominoex::rx_init()
met2 = 0.0;
counter = 0;
phase[0] = 0.0;
for (int i = 0; i < NUMFFTS; i++)
for (int i = 0; i < MAXFFTS; i++)
phase[i+1] = 0.0;
put_MODEstatus(mode);
put_sec_char(0);
syncfilter->reset();
datashreg = 1;
for (int i = 0; i < VBINS; i++) vbins[i] = 0;
}
void dominoex::reset_filters()
@ -100,16 +105,23 @@ dominoex::~dominoex()
{
if (hilbert) delete hilbert;
for (int i = 0; i < NUMFFTS; i++) {
for (int i = 0; i < MAXFFTS; i++) {
if (binsfft[i]) delete binsfft[i];
}
for (int i = 0; i < SCOPESIZE; i++) {
if (vidfilter[i]) delete vidfilter[i];
}
if (syncfilter) delete syncfilter;
if (pipe) delete [] pipe;
if (fft) delete fft;
if (MuPskRxinlv) delete MuPskRxinlv;
if (MuPskTxinlv) delete MuPskTxinlv;
if (MuPskDec) delete MuPskDec;
if (MuPskEnc) delete MuPskEnc;
}
dominoex::dominoex(trx_mode md)
@ -168,23 +180,26 @@ dominoex::dominoex(trx_mode md)
hilbert = new C_FIR_filter();
hilbert->init_hilbert(37, 1);
for (int i = 0; i < NUMFFTS; i++) {
paths = progdefaults.DOMINOEX_PATHS;
for (int i = 0; i < MAXFFTS; i++)
binsfft[i] = new sfft (symlen, lotone, hitone);
}
// fft filter at first if frequency
fft = new fftfilt( (FIRSTIF - 0.5 * progdefaults.DOMINOEX_BW * bandwidth) / samplerate,
(FIRSTIF + 0.5 * progdefaults.DOMINOEX_BW * bandwidth)/ samplerate,
1024 );
for (int i = 0; i < SCOPESIZE; i++)
vidfilter[i] = new Cmovavg(16);
syncfilter = new Cmovavg(8);
twosym = 2 * symlen;
pipe = new domrxpipe[twosym];
scopedata.alloc(SCOPESIZE);
videodata.alloc((NUMFFTS * NUMTONES * 2 * (doublespaced?2:1) ));
videodata.alloc((MAXFFTS * NUMTONES * 2 * (doublespaced?2:1) ));
pipeptr = 0;
@ -197,6 +212,16 @@ dominoex::dominoex(trx_mode md)
prev1symbol = prev2symbol = 0;
MuPskEnc = new encoder (K, POLY1, POLY2);
MuPskDec = new viterbi (K, POLY1, POLY2);
MuPskDec->settraceback (45);
MuPskDec->setchunksize (1);
MuPskTxinlv = new interleave (-1, INTERLEAVE_FWD);
MuPskRxinlv = new interleave (-1, INTERLEAVE_REV);
bitstate = 0;
symbolpair[0] = symbolpair[1] = 0;
datashreg = 1;
init();
}
@ -208,12 +233,12 @@ complex dominoex::mixer(int n, complex in)
complex z;
double f;
// first IF mixer (n == 0) plus
// NUMFFTS mixers are supported each separated by 1/NUMFFTS bin size
// n == 1, 2, 3, 4 ... NUMFFTS
// MAXFFTS mixers are supported each separated by 1/MAXFFTS bin size
// n == 1, 2, 3, 4 ... MAXFFTS
if (n == 0)
f = frequency - FIRSTIF;
else
f = FIRSTIF - BASEFREQ - bandwidth/2 + (samplerate / symlen) * (1.0 * n / NUMFFTS);
f = FIRSTIF - BASEFREQ - bandwidth/2 + (samplerate / symlen) * (1.0 * n / paths );
z.re = cos(phase[n]);
z.im = sin(phase[n]);
z = z * in;
@ -235,20 +260,9 @@ void dominoex::recvchar(int c)
put_rx_char(c & 0xFF);
}
void dominoex::decodesymbol()
void dominoex::decodeDomino(int c)
{
int c, sym, ch;
double fdiff;
// Decode the IFK+ sequence, which results in a single nibble
fdiff = currsymbol - prev1symbol;
if (reverse) fdiff = -fdiff;
if (doublespaced) fdiff /= 2 * NUMFFTS;
else fdiff /= NUMFFTS;
c = (int)floor(fdiff + .5) - 2;
if (c < 0) c += NUMTONES;
int sym, ch;
// If the new symbol is the start of a new character (MSB is low), complete the previous character
if (!(c & 0x8)) {
if (symcounter <= MAX_VARICODE_LEN) {
@ -271,14 +285,33 @@ void dominoex::decodesymbol()
symcounter++;
if (symcounter > MAX_VARICODE_LEN + 1)
symcounter = MAX_VARICODE_LEN + 1;
}
void dominoex::decodesymbol()
{
int c;
double fdiff;
// Decode the IFK+ sequence, which results in a single nibble
fdiff = currsymbol - prev1symbol;
if (reverse) fdiff = -fdiff;
if (doublespaced) fdiff /= 2 * paths;
else fdiff /= paths;
c = (int)floor(fdiff + .5) - 2;
if (c < 0) c += NUMTONES;
if (progdefaults.DOMINOEX_FEC)
decodeMuPskEX(c);
else
decodeDomino(c);
}
int dominoex::harddecode()
{
double x, max = 0.0;
int symbol = 0;
for (int i = 0; i < (NUMFFTS * NUMTONES * 2 * (doublespaced?2:1) ); i++) {
for (int i = 0; i < (paths * NUMTONES * 2 * (doublespaced ? 2 : 1) ); i++) {
x = pipe[pipeptr].vector[i].mag();
if (x > max) {
max = x;
@ -294,16 +327,16 @@ void dominoex::update_syncscope()
double max = 0, min = 1e6, range, mag;
// dom waterfall
memset(videodata, 0, (NUMFFTS * NUMTONES * 2 * (doublespaced?2:1) ) * sizeof(double));
memset(videodata, 0, (paths * NUMTONES * 2 * (doublespaced?2:1) ) * sizeof(double));
if (!progStatus.sqlonoff || metric >= progStatus.sldrSquelchValue) {
for (int i = 0; i < (NUMFFTS * NUMTONES * 2 * (doublespaced?2:1) ); i++ ) {
for (int i = 0; i < (paths * NUMTONES * 2 * (doublespaced?2:1) ); i++ ) {
mag = pipe[pipeptr].vector[i].mag();
if (max < mag) max = mag;
if (min > mag) min = mag;
}
range = max - min;
for (int i = 0; i < (NUMFFTS * NUMTONES * 2 * (doublespaced?2:1) ); i++ ) {
for (int i = 0; i < (paths * NUMTONES * 2 * (doublespaced?2:1) ); i++ ) {
if (range > 2) {
mag = (pipe[pipeptr].vector[i].mag() - min) / range + 0.0001;
mag = 1 + 2 * log10(mag);
@ -313,7 +346,7 @@ void dominoex::update_syncscope()
videodata[i] = 255*mag;
}
}
set_video(videodata, (NUMFFTS * NUMTONES * 2 * (doublespaced?2:1) ), false);
set_video(videodata, (paths * NUMTONES * 2 * (doublespaced?2:1) ), false);
videodata.next();
// set_scope(scopedata, twosym);
@ -324,7 +357,6 @@ void dominoex::update_syncscope()
for (unsigned int i = 0, j = 0; i < SCOPESIZE; i++) {
j = (pipeptr + i * twosym / SCOPESIZE + 1) % (twosym);
scopedata[i] = vidfilter[i]->run(pipe[j].vector[prev1symbol].mag());
// scopedata[i] = pipe[j].vector[prev1symbol].mag();
}
}
set_scope(scopedata, SCOPESIZE);
@ -333,7 +365,8 @@ void dominoex::update_syncscope()
void dominoex::synchronize()
{
int syn = -1;
// int syn = -1;
double syn = -1;
double val, max = 0.0;
if (currsymbol == prev1symbol)
@ -349,6 +382,8 @@ void dominoex::synchronize()
}
j = (j + 1) % twosym;
}
syn = syncfilter->run(syn);
synccounter += (int) floor(1.0 * (syn - symlen) / NUMTONES + 0.5);
}
@ -358,11 +393,11 @@ void dominoex::eval_s2n()
if (currsymbol != prev1symbol && prev1symbol != prev2symbol) {
sig = pipe[pipeptr].vector[currsymbol].mag();
noise = 0.0;
for (int i = 0; i < NUMFFTS * NUMTONES * 2 * (doublespaced?2:1); i++) {
for (int i = 0; i < paths * NUMTONES * 2 * (doublespaced?2:1); i++) {
if (i != currsymbol)
noise += pipe[pipeptr].vector[i].mag();
}
noise /= (NUMFFTS * NUMTONES * 2 * (doublespaced?2:1) - 1);
noise /= (paths * NUMTONES * 2 * (doublespaced?2:1) - 1);
s2n = decayavg( s2n, sig / noise, 8);
@ -370,17 +405,22 @@ void dominoex::eval_s2n()
display_metric(metric);
snprintf(dommsg, sizeof(dommsg), "s/n %3.0f dB", metric / 3.0);
snprintf(dommsg, sizeof(dommsg), "s/n %3.0f dB", metric / 3.0 - 2.0);
put_Status1(dommsg);
}
}
int dominoex::rx_process(const double *buf, int len)
{
complex zref, z, *zp, *bins;
complex zref, z, *zp, *bins = 0;
int n;
if (filter_reset) reset_filters();
if (paths != progdefaults.DOMINOEX_PATHS) {
paths = progdefaults.DOMINOEX_PATHS;
reset_filters();
}
while (len) {
// create analytic signal at first IF
@ -392,21 +432,22 @@ int dominoex::rx_process(const double *buf, int len)
if (n) {
for (int i = 0; i < n; i++) {
// process NUMFFTS sets of sliding FFTs spaced at 1/NUMFFTS bin intervals each of which
// process MAXFFTS sets of sliding FFTs spaced at 1/MAXFFTS bin intervals each of which
// is a matched filter for the current symbol length
for (int n = 0; n < NUMFFTS; n++) {
// shift in frequency to base band for the sliding FFTs
for (int n = 0; n < paths; n++) {
// shift in frequency to base band for the sliding DFTs
z = mixer(n + 1, zp[i]);
bins = binsfft[n]->run(z);
// copy current vector to the pipe interleaving the FFT vectors
for (int i = 0; i < NUMTONES * 2 * (doublespaced ? 2 : 1); i++) {
pipe[pipeptr].vector[n + NUMFFTS * i] = bins[i];
pipe[pipeptr].vector[n + paths * i] = bins[i];
}
}
if (--synccounter <= 0) {
synccounter = symlen;
currsymbol = harddecode();
decodesymbol();
// MuPskSoftdecode(bins);
synchronize();
update_syncscope();
eval_s2n();
@ -437,47 +478,52 @@ int dominoex::get_secondary_char()
return chr;
}
void dominoex::sendtone(int tone, int duration)
{
double f, phaseincr;
f = tone * tonespacing + get_txfreq_woffset() - bandwidth / 2;
phaseincr = twopi * f / samplerate;
for (int j = 0; j < duration; j++) {
for (int i = 0; i < symlen; i++) {
outbuf[i] = cos(txphase);
txphase -= phaseincr;
if (txphase > M_PI)
txphase -= twopi;
else if (txphase < M_PI)
txphase += twopi;
}
ModulateXmtr(outbuf, symlen);
}
}
void dominoex::sendsymbol(int sym)
{
//static int first = 0;
complex z;
int tone;
double f, phaseincr;
tone = (txprevtone + 2 + sym) % NUMTONES;
txprevtone = tone;
if (reverse)
tone = (NUMTONES - 1) - tone;
f = tone * tonespacing + get_txfreq_woffset() - bandwidth / 2;
phaseincr = twopi * f / samplerate;
for (int i = 0; i < symlen; i++) {
outbuf[i] = cos(txphase);
txphase -= phaseincr;
if (txphase > M_PI)
txphase -= twopi;
else if (txphase < M_PI)
txphase += twopi;
}
ModulateXmtr(outbuf, symlen);
sendtone(tone, 1);
}
void dominoex::sendchar(unsigned char c, int secondary)
{
unsigned char *code = dominoex_varienc(c, secondary);
sendsymbol(code[0]);
if (progdefaults.DOMINOEX_FEC)
sendMuPskEX(c, secondary);
else {
unsigned char *code = dominoex_varienc(c, secondary);
sendsymbol(code[0]);
// Continuation nibbles all have the MSB set
for (int sym = 1; sym < 3; sym++) {
if (code[sym] & 0x8)
sendsymbol(code[sym]);
else
break;
}
for (int sym = 1; sym < 3; sym++) {
if (code[sym] & 0x8)
sendsymbol(code[sym]);
else
break;
}
}
if (!secondary)
put_echo_char(c);
}
@ -495,9 +541,13 @@ void dominoex::sendsecondary()
void dominoex::flushtx()
{
// if (progdefaults.DOMINOEX_FEC)
// MuPskFlushTx();
// else {
// flush the varicode decoder at the receiver end
for (int i = 0; i < 4; i++)
sendidle();
for (int i = 0; i < 4; i++)
sendidle();
// }
}
int dominoex::tx_process()
@ -506,6 +556,8 @@ int dominoex::tx_process()
switch (txstate) {
case TX_STATE_PREAMBLE:
if (progdefaults.DOMINOEX_FEC)
MuPskClearbits();
sendidle();
txstate = TX_STATE_START;
break;
@ -539,3 +591,215 @@ int dominoex::tx_process()
}
return 0;
}
//=============================================================================
// MultiPsk compatible FEC methods
//=============================================================================
//=============================================================================
// Varicode support methods
// MultiPsk varicode is based on a modified MFSK varicode table in which
// Character substition is used for secondary text. The resulting table does
// NOT contain the full ASCII character set as the primary. Many of the
// control codes and characters above 0x80 are lost.
//=============================================================================
// Convert from Secondary to Primary character
unsigned char dominoex::MuPskSec2Pri(int c)
{
if (c >= 'a' && c <= 'z') c -= 32;
if (c == 'À' || c == 'Á' || c == 'Â' || c == 'Ã' || c == 'Ä' || c == 'Å' ||
c == 'à' || c == 'á' || c == 'â' || c == 'ã' || c == 'ä' || c == 'å')
c = 'A';
if (c == 'ß') c = 'B';
if (c == 'Ç' || c == 'ç' || c == '©') c = 'C';
if (c == 'Ð' || c == '°') c = 'D';
if (c == 'Æ' || c == 'æ' || c == 'È' || c == 'É' || c == 'Ê' || c == 'Ë' ||
c == 'è' || c == 'é' || c == 'ê' || c == 'ë')
c = 'E';
if (c == 'ƒ') c = 'F';
if (c == 'Ì' || c == 'Í' || c == 'Î' || c == 'Ï' || c == 'ì' || c == 'í' ||
c == 'î' || c == 'ï' || c == '¡')
c = 'I';
if (c == '£') c = 'L';
if (c == 'Ñ' || c == 'ñ') c = 'N';
if (c == 'ô' || c == 'ö' || c == 'ò' || c == 'Ö' || c == 'ó' ||
c == 'Ó' || c == 'Ô' || c == 'Ò' || c == 'õ' || c == 'Õ')
c = 'O';
if (c == '®') c = 'R';
if (c == 'Ù' || c == 'Ú' || c == 'Û' || c == 'Ü' ||
c == 'ù' || c == 'ú' || c == 'û' || c == 252)
if (c == 'ü' || c == 'û' || c == 'ù' || c == 'Ü' ||
c == 'ú' || c == 'Ú' || c == 'Û' || c == 'Ù')
c = 'U';
if (c == '×') c = 'X';
if (c == 'ÿ' || c == 'ý' || c == 'Ý') c = 'Y';
if (c == 'Ø') c = '0';
if (c == '¹') c = '1';
if (c == '²') c = '2';
if (c == '³') c = '3';
if (c == '¿') c = '?';
if (c == '¡') c = '!';
if (c == '«') c = '<';
if (c == '»') c = '>';
if (c == '{') c = '(';
if (c == '}') c = ')';
if (c == '|') c = '\\';
if (c >= 'A' && c <= 'Z') c = c - 'A' + 127;
else if (c >= '0' && c <= '9') c = c - '0' + 14;
else if (c >= ' ' && c <= '"') c = c - ' ' + 1;
else if (c == '_') c = 4;
else if (c >= '$' && c <= '&') c = c - '$' + 5;
else if (c >= '\'' && c <= '*') c = c - '\'' + 9;
else if (c >= '+' && c <= '/') c = c - '+' + 24;
else if (c >= ':' && c <= '<') c = c - ':' + 29;
else if (c >= '=' && c <= '@') c = c - '=' + 153;
else if (c >= '[' && c <= ']') c = c - '[' + 157;
else c = '_';
return c;
}
// Convert Primary to Split Primary / Secondary character
unsigned int dominoex::MuPskPriSecChar(unsigned int c)
{
if (c >= 127 && c < 153) c += ('A' - 127) + 0x100;
else if (c >=14 && c < 24) c += ('0' - 14) + 0x100;
else if (c >= 1 && c < 4) c += (' ' - 1) + 0x100;
else if (c == 4) c = '_' + 0x100;
else if (c >= 5 && c < 8) c += ('$' - 5) + 0x100;
else if (c >= 9 && c < 13) c += ('\'' - 9) + 0x100;
else if (c >= 24 && c < 29) c += ('+' - 24) + 0x100;
else if (c >= 29 && c < 32) c += (':' - 29) + 0x100;
else if (c >= 153 && c < 157) c += ('=' - 153) + 0x100;
else if (c >= 157 && c < 160) c += ('[' - 157) + 0x100;
return c;
}
//=============================================================================
// Receive
//=============================================================================
void dominoex::decodeMuPskSymbol(unsigned char symbol)
{
int c, ch, met;
symbolpair[0] = symbolpair[1];
symbolpair[1] = symbol;
symcounter = symcounter ? 0 : 1;
if (symcounter) return;
c = MuPskDec->decode (symbolpair, &met);
if (c == -1)
return;
if (progStatus.sqlonoff && metric < progStatus.sldrSquelchValue)
return;
datashreg = (datashreg << 1) | !!c;
if ((datashreg & 7) == 1) {
ch = varidec(datashreg >> 1);
recvchar(MuPskPriSecChar(ch));
datashreg = 1;
}
}
void dominoex::MuPskSoftdecode(complex *bins)
{
}
void dominoex::decodeMuPskEX(int ch)
{
unsigned char symbols[4];
int c = ch;
for (int i = 0; i < 4; i++) {
if (c & 1 == 1) symbols[3-i] = 255;
else symbols[3-i] = -255;
c = c / 2;
}
MuPskRxinlv->symbols(symbols);
for (int i = 0; i < 4; i++) decodeMuPskSymbol(symbols[i]);
}
//=============================================================================
// Transmit
//=============================================================================
void dominoex::MuPskFlushTx()
{
// flush the varicode decoder at the other end
// flush the convolutional encoder and interleaver
sendsymbol(1);
for (int i = 0; i < 107; i++)
sendsymbol(0);
bitstate = 0;
}
void dominoex::MuPskClearbits()
{
int data = MuPskEnc->encode(0);
for (int k = 0; k < 100; k++) {
for (int i = 0; i < 2; i++) {
bitshreg = (bitshreg << 1) | ((data >> i) & 1);
bitstate++;
if (bitstate == 4) {
MuPskTxinlv->bits(&bitshreg);
bitstate = 0;
bitshreg = 0;
}
}
}
}
// Send MultiPsk FEC varicode with minimalist interleaver
void dominoex::sendMuPskEX(unsigned char c, int secondary)
{
const char *code;
if (secondary == 1)
c = MuPskSec2Pri(c);
else {
if (c == 10)
return;
if ( (c >= 1 && c <= 7) || (c >= 9 && c <= 12) || (c >= 14 && c <= 31) ||
(c >= 127 && c <= 159))
c = '_';
}
code = varienc(c);
//if (secondary == 0)
//std::cout << (int)c << " ==> " << code << " ==> ";
while (*code) {
int data = MuPskEnc->encode(*code++ - '0');
//std::cout << (int)data << " ";
for (int i = 0; i < 2; i++) {
bitshreg = (bitshreg << 1) | ((data >> i) & 1);
bitstate++;
if (bitstate == 4) {
MuPskTxinlv->bits(&bitshreg);
//std::cout << "(" << bitshreg << ") ";
sendsymbol(bitshreg);
//decodeMuPskEX(bitshreg);
bitstate = 0;
bitshreg = 0;
}
}
}
//std::cout << std::endl;
}

Wyświetl plik

@ -1,76 +1,82 @@
#include <config.h>
#include <string>
#include "fileselect.h"
#include <FL/fl_ask.H>
#include <FL/Fl_Native_File_Chooser.H>
using namespace std;
static Fl_Native_File_Chooser* chooser = 0;
static Fl_Native_File_Chooser chooser;
static std::string filename;
static const char* get_file(void)
{
switch (chooser->show()) {
const char* preset = chooser.preset_file();
if (preset && *preset != '/' && chooser.directory()) {
filename = chooser.directory();
filename.append("/").append(preset);
chooser.preset_file(filename.c_str());
}
switch (chooser.show()) {
case -1:
fl_alert("%s", chooser->errmsg());
fl_alert("%s", chooser.errmsg());
// fall through
case 1:
return NULL;
default:
return chooser->filename();
filename = chooser.filename();
string::size_type i = filename.rfind('/');
if (i != string::npos)
chooser.directory(filename.substr(0, i).c_str());
return filename.c_str();
}
}
const char* file_select(const char* title, const char* filter, const char* def, int* fsel)
{
if (!chooser)
chooser = new Fl_Native_File_Chooser;
chooser->title(title);
chooser->filter(filter);
chooser.title(title);
chooser.filter(filter);
if (def)
chooser->preset_file(def);
chooser->options(Fl_Native_File_Chooser::PREVIEW);
chooser->type(Fl_Native_File_Chooser::BROWSE_FILE);
chooser.preset_file(def);
chooser.options(Fl_Native_File_Chooser::PREVIEW);
chooser.type(Fl_Native_File_Chooser::BROWSE_FILE);
const char* fn = get_file();
if (fsel)
*fsel = chooser->filter_value();
*fsel = chooser.filter_value();
return fn;
}
const char* file_saveas(const char* title, const char* filter, const char* def, int* fsel)
{
if (!chooser)
chooser = new Fl_Native_File_Chooser;
chooser->title(title);
chooser->filter(filter);
chooser.title(title);
chooser.filter(filter);
if (def)
chooser->preset_file(def);
chooser->options(Fl_Native_File_Chooser::SAVEAS_CONFIRM |
chooser.preset_file(def);
chooser.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM |
Fl_Native_File_Chooser::NEW_FOLDER |
Fl_Native_File_Chooser::PREVIEW);
chooser->type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
const char* fn = get_file();
if (fsel)
*fsel = chooser->filter_value();
*fsel = chooser.filter_value();
return fn;
}
const char* dir_select(const char* title, const char* filter, const char* def)
{
if (!chooser)
chooser = new Fl_Native_File_Chooser;
chooser->title(title);
chooser->filter(filter);
chooser.title(title);
chooser.filter(filter);
if (def)
chooser->directory(def);
chooser->options(Fl_Native_File_Chooser::NEW_FOLDER |
chooser.directory(def);
chooser.options(Fl_Native_File_Chooser::NEW_FOLDER |
Fl_Native_File_Chooser::PREVIEW);
chooser->type(Fl_Native_File_Chooser::BROWSE_DIRECTORY);
chooser.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY);
return get_file();
}

Wyświetl plik

@ -44,7 +44,15 @@ const char *state_names[] = {
// first string (sname), so its length should be a multiple of 2.
const struct mode_info_t mode_info[NUM_MODES] = {
{ MODE_CW, &cw_modem, "CW", "CW", "CW", "CW" },
{ MODE_DOMINOEX4, &dominoex4_modem, "DomEX4", "DominoEX 4", "DOMINOEX4", "DOMINO" }, // These aren't Domino FEC, right?
{ MODE_DEX4, &dex4_modem, "DEX4", "DEX 4", "DEX4", "DEX" },
{ MODE_DEX5, &dex5_modem, "DEX5", "DEX 5", "DEX5", "DEX" },
{ MODE_DEX8, &dex8_modem, "DEX8", "DEX 8", "DEX8", "DEX" },
{ MODE_DEX11, &dex11_modem, "DEX11", "DEX 11", "DEX11", "DEX" },
{ MODE_DEX16, &dex16_modem, "DEX16", "DEX 16", "DEX16", "DEX" },
{ MODE_DEX22, &dex22_modem, "DEX22", "DEX 22", "DEX22", "DEX" },
{ MODE_DOMINOEX4, &dominoex4_modem, "DomEX4", "DominoEX 4", "DOMINOEX4", "DOMINO" },
{ MODE_DOMINOEX5, &dominoex5_modem, "DomEX5", "DominoEX 5", "DOMINOEX5", "DOMINO" },
{ MODE_DOMINOEX8, &dominoex8_modem, "DomEX8", "DominoEX 8", "DOMINOEX8", "DOMINO" },
{ MODE_DOMINOEX11, &dominoex11_modem, "DomX11", "DominoEX 11", "DOMINOEX11", "DOMINO" },

Wyświetl plik

@ -137,11 +137,17 @@ extern Fl_Group *tabCWQSK;
extern Fl_Check_Button *btnQSK;
extern Fl_Counter *cntPreTiming;
extern Fl_Counter *cntPostTiming;
extern Fl_Group *tabDEX;
extern Fl_Input *txtDEXSecondary;
extern Fl_Counter *valDEX_BW;
extern Fl_Check_Button *valDEX_FILTER;
extern Fl_Counter *valDEX_PATHS;
extern Fl_Group *tabDomEX;
extern Fl_Input *txtSecondary;
extern Fl_Button *btnRestartDomEX;
extern Fl_Counter *valDominoEX_BW;
extern Fl_Check_Button *valDominoEX_FILTER;
extern Fl_Check_Button *chkDominoEX_FEC;
extern Fl_Counter *valDominoEX_PATHS;
extern Fl_Group *tabFeld;
#include "fontdef.h"
extern Fl_Choice *selHellFont;

Wyświetl plik

@ -72,10 +72,17 @@ struct configuration {
int oliviabw;
int oliviasmargin;
int oliviasinteg;
bool olivia8bit;
bool olivia8bit;
// DEX
double DEX_BW;
bool DEX_FILTER;
string DEXsecText;
int DEX_PATHS;
// DOMINOEX
double DOMINOEX_BW;
bool DOMINOEX_FILTER;
bool DOMINOEX_FEC;
int DOMINOEX_PATHS;
// MT63
bool mt63_8bit;
int mt63_interleave;

162
src/include/dex.h 100644
Wyświetl plik

@ -0,0 +1,162 @@
//
// dex.h -- dex modem
//
// Copyright (C) 2008
// David Freese (w1hkj@w1hkj.com)
//
// 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 _dex_H
#define _dex_H
#include <string>
#include "complex.h"
#include "trx.h"
#include "fft.h"
#include "filters.h"
#include "fftfilt.h"
#include "dominovar.h"
#include "mbuffer.h"
// NASA coefficients for viterbi encode/decode algorithms
#define DEX_K 7
#define DEX_POLY1 0x6d
#define DEX_POLY2 0x4f
//#include "mfskvaricode.h"
#include "interleave.h"
#include "viterbi.h"
using namespace std;
#define DEXNUMMTONES 18
#define DEXMAXFFTS 8
#define DEXBASEFREQ 500.0
#define DEXFIRSTIF 1000.0
#define DEXSCOPESIZE 64
struct DEXrxpipe {
complex vector[DEXMAXFFTS * DEXNUMMTONES * 6];
};
class dex : public modem {
public:
enum {
TX_STATE_PREAMBLE,
TX_STATE_START,
TX_STATE_DATA,
TX_STATE_END,
TX_STATE_FLUSH
};
protected:
// common variables
double phase[DEXMAXFFTS + 1];
double txphase;
int symlen;
int doublespaced;
double tonespacing;
int counter;
unsigned int twosym;
int paths;
// rx variables
C_FIR_filter *hilbert;
sfft *binsfft[DEXMAXFFTS];
fftfilt *fft;
Cmovavg *vidfilter[DEXSCOPESIZE];
Cmovavg *syncfilter;
DEXrxpipe *pipe;
unsigned int pipeptr;
unsigned int datashreg;
mbuffer<double, 0, 2> scopedata;
mbuffer<double, 0, 2> videodata;
complex currvector;
int currsymbol;
int prev1symbol;
int prev2symbol;
double met1;
double met2;
double sig;
double noise;
double s2n;
int synccounter;
unsigned char symbolbuf[MAX_VARICODE_LEN];
int symcounter;
int symbolbit;
bool filter_reset;
// tx variables
int txstate;
int txprevtone;
unsigned int bitshreg;
string strSecXmtText;
unsigned int cptr;
viterbi *Dec;
interleave *Rxinlv;
encoder *Enc;
interleave *Txinlv;
int bitstate;
unsigned char symbolpair[2];
private:
complex mixer(int n, complex in);
// Rx
void recvchar(int c);
void decodesymbol();
int harddecode();
void update_syncscope();
void synchronize();
void reset_afc();
void eval_s2n();
int get_secondary_char();
void reset_filters();
void decodePairs(unsigned char symbol);
void decodeEX(int c);
// Tx
void sendtone(int tone, int duration);
void sendsymbol(int sym);
void sendchar(unsigned char c, int secondary);
void sendidle();
void sendsecondary();
void flushtx();
void Clearbits();
public:
dex (trx_mode md);
~dex ();
void init();
void rx_init();
void tx_init(SoundBase *sc);
void restart();
int rx_process(const double *buf, int len);
int tx_process();
};
#endif

Wyświetl plik

@ -0,0 +1,30 @@
//
// dexvaricode.h -- DEX Varicode
//
// Copyright (C) 2008
// Dave Freese, W1HKJ
//
// This file is part of fldigi.
//
// 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 _DEXVARICODE_H
#define _DEXVARICODE_H
extern const char *dexvarienc(int c, int secondary);
extern int dexvaridec(unsigned int symbol);
#endif

Wyświetl plik

@ -36,18 +36,31 @@
#include "dominovar.h"
#include "mbuffer.h"
// NASA coefficients for viterbi encode/decode algorithms
#define K 7
#define POLY1 0x6d
#define POLY2 0x4f
//#include "mfskvaricode.h"
#include "interleave.h"
#include "viterbi.h"
using namespace std;
#define NUMTONES 18
//#define NUMFFTS 4
#define NUMFFTS 8
//#define MAXFFTS 4
#define MAXFFTS 8
//#define BASEFREQ 1000.0
#define BASEFREQ 500.0
#define FIRSTIF 1000.0
#define SCOPESIZE 64
// NUMBER OF BINS IN VIRTUAL MFSK array
#define VBINS 16
struct domrxpipe {
complex vector[NUMFFTS * NUMTONES * 6];
complex vector[MAXFFTS * NUMTONES * 6];
};
class dominoex : public modem {
@ -61,19 +74,21 @@ public:
};
protected:
// common variables
double phase[NUMFFTS + 1];
double phase[MAXFFTS + 1];
double txphase;
int symlen;
int doublespaced;
double tonespacing;
int counter;
unsigned int twosym;
unsigned int twosym;
int paths;
// rx variables
C_FIR_filter *hilbert;
sfft *binsfft[NUMFFTS];
sfft *binsfft[MAXFFTS];
fftfilt *fft;
Cmovavg *vidfilter[SCOPESIZE];
Cmovavg *syncfilter;
domrxpipe *pipe;
unsigned int pipeptr;
@ -108,16 +123,26 @@ protected:
unsigned int bitshreg;
string strSecXmtText;
viterbi *MuPskDec;
interleave *MuPskRxinlv;
encoder *MuPskEnc;
interleave *MuPskTxinlv;
int bitstate;
int vbins[VBINS];
unsigned char symbolpair[2];
private:
complex mixer(int n, complex in);
void recvchar(int c);
void decodesymbol();
void decodeDomino(int c);
int harddecode();
void update_syncscope();
void synchronize();
void afc();
void reset_afc();
void eval_s2n();
void sendtone(int tone, int duration);
void sendsymbol(int sym);
void sendchar(unsigned char c, int secondary);
void sendidle();
@ -125,6 +150,18 @@ private:
void flushtx();
int get_secondary_char();
void reset_filters();
// MultiPsk FEC scheme
// Rx
unsigned int MuPskPriSecChar(unsigned int c);
void decodeMuPskSymbol(unsigned char symbol);
void MuPskSoftdecode(complex *bins);
void decodeMuPskEX(int c);
// Tx
unsigned char MuPskSec2Pri(int c);
void sendMuPskEX(unsigned char c, int secondary);
void MuPskClearbits();
void MuPskFlushTx();
public:
dominoex (trx_mode md);
~dominoex ();

Wyświetl plik

@ -133,6 +133,7 @@ extern int get_secondary_char();
extern void put_echo_char(unsigned int data);
extern void resetRTTY();
extern void resetOLIVIA();
extern void resetDEX();
extern void resetDOMEX();
extern void resetSoundCard();
extern void restoreFocus();

Wyświetl plik

@ -51,6 +51,13 @@ enum {
MODE_CW,
MODE_DEX4,
MODE_DEX5,
MODE_DEX8,
MODE_DEX11,
MODE_DEX16,
MODE_DEX22,
MODE_DOMINOEX4,
MODE_DOMINOEX5,
MODE_DOMINOEX8,

Wyświetl plik

@ -83,6 +83,8 @@ struct history {
class mfsk : public modem {
#define SCOPESIZE 64
friend void updateTxPic(unsigned char data, mfsk *me);
friend void cb_picRxClose( Fl_Widget *w, void *who);
friend void cb_picRxAbort( Fl_Widget *w, void *who);
@ -127,6 +129,7 @@ protected:
Cmovavg *afcfilt;
Cmovavg *met1filt;
Cmovavg *met2filt;
Cmovavg *vidfilter[SCOPESIZE];
viterbi *dec1;
viterbi *dec2;
@ -202,7 +205,7 @@ protected:
void synchronize();
void afc();
void reset_afc();
void eval_s2n(complex, complex);
void eval_s2n();
void sendsymbol(int sym);
void sendbit(int bit);
void sendchar(unsigned char c);

Wyświetl plik

@ -194,6 +194,12 @@ extern modem *qpsk125_modem;
extern modem *qpsk250_modem;
extern modem *rtty_modem;
extern modem *olivia_modem;
extern modem *dex4_modem;
extern modem *dex5_modem;
extern modem *dex8_modem;
extern modem *dex11_modem;
extern modem *dex16_modem;
extern modem *dex22_modem;
extern modem *dominoex4_modem;
extern modem *dominoex5_modem;
extern modem *dominoex8_modem;

Wyświetl plik

@ -231,7 +231,7 @@ public:
private:
void src_data_reset(int mode);
void resample(int mode, float* inbuf, float* outbuf, size_t count, size_t max = 0);
static long src_read_cb(void* arg, float** data);
size_t resample_write(float* buf, size_t count);
void init_stream(unsigned dir);
void start_stream(unsigned dir);
@ -239,6 +239,7 @@ private:
bool full_duplex_device(const PaDeviceInfo* dev);
double find_srate(unsigned dir);
void pa_perror(int err, const char* str = 0);
static void init_hostapi_ext(void);
static PaStreamCallback stream_process;
static PaStreamFinishedCallback stream_stopped;
@ -262,11 +263,14 @@ private:
unsigned frames_per_buffer;
double dev_sample_rate;
double src_ratio;
sem_t* rwsem;
sem_t* csem;
int state;
ringbuffer<float>* rb;
size_t blocksize;
size_t advance;
} sd[2];
};
@ -291,13 +295,17 @@ public:
private:
void src_data_reset(int mode);
void resample(int mode, float *buf, size_t count, size_t max = 0);
static long src_read_cb(void* arg, float** data);
size_t resample_write(float* buf, size_t count);
private:
double dev_sample_rate[2];
pa_simple* stream[2];
pa_sample_spec stream_params;
struct stream_data {
pa_simple* stream;
pa_sample_spec stream_params;
pa_stream_direction_t dir;
double src_ratio;
size_t blocksize;
} sd[2];
float* fbuf;
};

Wyświetl plik

@ -1,16 +1,10 @@
#ifndef _status_H
#define _status_H
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include "main.h"
#include "globals.h"
struct status {
int lastmode;
trx_mode lastmode;
int mainX;
int mainY;
int mainW;
@ -39,17 +33,12 @@ struct status {
bool scopeVisible;
int scopeW;
int scopeH;
bool bLastStateRead;
public:
void saveModeState(trx_mode m);
void initLastState();
void saveLastState();
void loadLastState();
friend std::istream &operator>>(std::istream &stream, status &c);
friend std::ostream &operator<<(std::ostream &ostream, status c);
};
extern status progStatus;

Wyświetl plik

@ -35,7 +35,11 @@
interleave::interleave (int _size, int dir)
{
size = _size;
if (size == 4) depth = 10;
if (size == -1) { // dominoEX interleaver
size = 4;
depth = 4;
} else if (size == 4)
depth = 10;
else depth = 5;
direction = dir;
table = new unsigned char [depth * size * size];

Wyświetl plik

@ -99,6 +99,9 @@ mfsk::~mfsk()
if (met1filt) delete met1filt;
if (met2filt) delete met2filt;
if (xmtimg) delete [] xmtimg;
for (int i = 0; i < SCOPESIZE; i++) {
if (vidfilter[i]) delete vidfilter[i];
}
deleteRxViewer();
deleteTxViewer();
}
@ -132,6 +135,9 @@ mfsk::mfsk(trx_mode mfsk_mode) : modem()
afcfilt = new Cmovavg(AFC_COUNT);
met1filt = new Cmovavg(32);
met2filt = new Cmovavg(32);
for (int i = 0; i < SCOPESIZE; i++)
vidfilter[i] = new Cmovavg(16);
pipe = new rxpipe[ 2 * symlen ];
@ -150,8 +156,8 @@ mfsk::mfsk(trx_mode mfsk_mode) : modem()
bw = (numtones - 1) * tonespacing;
cf = 1000.0 + bw / 2.0;
flo = (cf - bw/2 - tonespacing) / MFSKSampleRate;
fhi = (cf + bw/2 + tonespacing) / MFSKSampleRate;
flo = (cf - bw/2 - 2 * tonespacing) / MFSKSampleRate;
fhi = (cf + bw/2 + 2 * tonespacing) / MFSKSampleRate;
bpfilt = new C_FIR_filter();
bpfilt->init_bandpass (127, 1, flo, fhi);
@ -344,7 +350,7 @@ void mfsk::decodesymbol(unsigned char symbol)
if (met1 < met2)
return;
metric = met1 / 2.5;
metric = met1 / 2.0;
} else {
if ((c = dec2->decode(symbolpair, &met)) == -1)
return;
@ -354,7 +360,7 @@ void mfsk::decodesymbol(unsigned char symbol)
if (met2 < met1)
return;
metric = met2 / 2.5;
metric = met2 / 2.0;
}
display_metric(metric);
@ -448,14 +454,14 @@ void mfsk::update_syncscope()
if (max == 0.0) max = 1e10;
memset(scopedata, 0, 2 * symlen * sizeof(double));
if (!progStatus.sqlonoff || metric >= progStatus.sldrSquelchValue)
for (int i = 0; i < pipelen; i++) {
j = (pipeptr - i);
if (j < 0) j += pipelen;
scopedata[i] = (pipe[j].vector[prev1symbol]).mag() / max;
for (unsigned int i = 0; i < SCOPESIZE; i++) {
j = (pipeptr + i * pipelen / SCOPESIZE + 1) % (pipelen);
scopedata[i] = vidfilter[i]->run(pipe[j].vector[prev1symbol].mag());
}
set_scope(scopedata, pipelen, false);
set_scope(scopedata, SCOPESIZE);
scopedata.next(); // change buffers
snprintf(mfskmsg, sizeof(mfskmsg), "s/n %3.0f dB", 20.0 * log10(s2n) );
snprintf(mfskmsg, sizeof(mfskmsg), "s/n %3.0f dB", 20.0 * log10(s2n) - 9.0 );
put_Status1(mfskmsg);
}
@ -503,6 +509,9 @@ void mfsk::afc()
reset_afc();
sigsearch = 0;
}
if (prev1symbol != currsymbol)
return;
if (pipeptr == 0) {
prevvector = pipe[2*symlen - 1].vector[currsymbol];
} else {
@ -522,15 +531,17 @@ void mfsk::afc()
}
}
void mfsk::eval_s2n(complex c, complex n)
void mfsk::eval_s2n()
{
sig = c.mag(); // signal + noise energy
noise = n.mag() + 1e-20; // noise energy
if (metric > progStatus.sldrSquelchValue)
s2n = decayavg( s2n, fabs(sig / noise), 16 );
else
s2n = decayavg( s2n, 1.0, 16 );
sig = pipe[pipeptr].vector[currsymbol].mag();
noise = 0.0;
for (int i = 0; i < numtones; i++) {
if (i != currsymbol)
noise += pipe[pipeptr].vector[i].mag();
}
noise /= (numtones - 1);
if (noise > 0)
s2n = decayavg ( s2n, sig / noise, 16 );
}
int mfsk::rx_process(const double *buf, int len)
@ -604,7 +615,7 @@ int mfsk::rx_process(const double *buf, int len)
// frequency tracking
afc();
eval_s2n(currvector, bins[(currsymbol + numtones/2) % numtones]);
eval_s2n();
// decode symbol
softdecode(bins);
// symbol sync

Wyświetl plik

@ -77,10 +77,17 @@ configuration progdefaults = {
2, // int oliviabw;
8, // int oliviasmargin
4, // int oliviasinteg
false, // bool olivia8bit
false, // bool olivia8bit
// DEX
2.0, // double DEX_BW;
true, // bool DEX_FILTER;
"fldigi-dex ", // string DEXsecText;
5, // int DEX_PATHS;
// DOMINOEX
2.0, // double DOMINOEX_BW;
false, // bool DOMINOEX_FILTER
true, // bool DOMINOEX_FILTER
false, // bool DOMINOEX_FEC
5, // int DOMINOEX_PATHS
// MT63
false, // bool mt63_8bit;
32, // int mt63_interleave;
@ -243,7 +250,8 @@ enum TAG { \
CWTRACK, CWRISETIME, CWDASH2DOT,
XQSK, CWPRE, CWPOST, CWID, CWIDWPM,
OLIVIATONES, OLIVIABW, OLIVIASMARGIN, OLIVIASINTEG, OLIVIA8BIT,
DOMINOEXBW, DOMINOEXFILTER,
DEXBW, DEXFILTER, DEXSECTEXT, DEXPATHS,
DOMINOEXBW, DOMINOEXFILTER, DOMINOEXFEC, DOMINOEXPATHS,
FELDFONTNBR, FELDIDLE,
WFPREFILTER, LATENCY,
USECURSORLINES, USECURSORCENTERLINE, USEBWTRACKS,
@ -382,8 +390,17 @@ void configuration::writeDefaultsXML()
writeXMLint(f, "OLIVIASMARGIN", oliviasmargin);
writeXMLint(f, "OLIVIASINTEG", oliviasinteg);
writeXMLbool(f, "OLIVIA8BIT", olivia8bit);
writeXMLdbl(f, "DEXBW", DEX_BW);
writeXMLbool(f, "DEXFILTER", DEX_FILTER);
writeXMLstr(f, "DEXSECTEXT", DEXsecText);
writeXMLint(f, "DEXPATHS", DEX_PATHS);
writeXMLdbl(f, "DOMINOEXBW", DOMINOEX_BW);
writeXMLbool(f, "DOMINOEXFILTER", DOMINOEX_FILTER);
writeXMLbool(f, "DOMINOEXFEC", DOMINOEX_FEC);
writeXMLint(f, "DOMINOEXPATHS", DOMINOEX_PATHS);
writeXMLint(f, "FELDFONTNBR", feldfontnbr);
writeXMLbool(f, "FELDIDLE", FELD_IDLE);
@ -671,12 +688,30 @@ bool configuration::readDefaultsXML()
case OLIVIA8BIT :
olivia8bit = atoi(xml->getNodeData());
break;
case DEXBW :
DEX_BW = atof(xml->getNodeData());
break;
case DEXFILTER :
DEX_FILTER = atoi(xml->getNodeData());
break;
case DEXSECTEXT :
DEXsecText = xml->getNodeData();
break;
case DEXPATHS :
DEX_PATHS = atoi(xml->getNodeData());
break;
case DOMINOEXBW :
DOMINOEX_BW = atof(xml->getNodeData());
break;
case DOMINOEXFILTER :
DOMINOEX_FILTER = atoi(xml->getNodeData());
break;
case DOMINOEXFEC :
DOMINOEX_FEC = atoi(xml->getNodeData());
break;
case DOMINOEXPATHS :
DOMINOEX_PATHS = atoi(xml->getNodeData());
break;
case FELDFONTNBR :
feldfontnbr = atoi(xml->getNodeData());
break;
@ -1027,8 +1062,14 @@ bool configuration::readDefaultsXML()
else if (!strcmp("OLIVIASMARGIN", nodeName)) tag = OLIVIASMARGIN;
else if (!strcmp("OLIVIASINTEG", nodeName)) tag = OLIVIASINTEG;
else if (!strcmp("OLIVIA8BIT", nodeName)) tag = OLIVIA8BIT;
else if (!strcmp("DEXBW", nodeName)) tag = DEXBW;
else if (!strcmp("DEXFILTER", nodeName)) tag = DEXFILTER;
else if (!strcmp("DEXSECTEXT", nodeName)) tag = DEXSECTEXT;
else if (!strcmp("DEXPATHS", nodeName)) tag = DEXPATHS;
else if (!strcmp("DOMINOEXBW", nodeName)) tag = DOMINOEXBW;
else if (!strcmp("DOMINOEXFILTER", nodeName)) tag = DOMINOEXFILTER;
else if (!strcmp("DOMINOEXFEC", nodeName)) tag = DOMINOEXFEC;
else if (!strcmp("DOMINOEXPATHS", nodeName)) tag = DOMINOEXPATHS;
else if (!strcmp("FELDFONTNBR", nodeName)) tag = FELDFONTNBR;
else if (!strcmp("FELDIDLE", nodeName)) tag = FELDIDLE;
else if (!strcmp("WFPREFILTER", nodeName)) tag = WFPREFILTER;
@ -1210,6 +1251,7 @@ void configuration::saveDefaults() {
myQth = inpMyQth->value();
myLocator = inpMyLocator->value();
secText = txtSecondary->value();
DEXsecText = txtDEXSecondary->value();
PTTdev = inpTTYdev->value();
for (int i = 0; i < 9; i++) {
@ -1237,9 +1279,17 @@ int configuration::setDefaults() {
ContestDigits = (int)nbrContestDigits->value();
txtSecondary->value(secText.c_str());
txtDEXSecondary->value(DEXsecText.c_str());
valDEX_BW->value(DEX_BW);
valDEX_FILTER->value(DEX_FILTER);
valDEX_PATHS->value(DEX_PATHS);
valDominoEX_BW->value(DOMINOEX_BW);
valDominoEX_FILTER->value(DOMINOEX_FILTER);
chkDominoEX_FEC->value(DOMINOEX_FEC);
valDominoEX_PATHS->value(DOMINOEX_PATHS);
for (int i = 0; i < 5; i++) {
btnPTT[i]->value(0);
btnPTT[i]->activate();

Wyświetl plik

@ -47,7 +47,7 @@ void pstack(int fd, unsigned skip)
void pstack_maybe(void)
{
static bool trace = getenv("TRACE_LOCKS");
static bool trace = getenv("FLDIGI_TRACE_LOCKS");
if (trace)
pstack(STDERR_FILENO, 1);
@ -55,14 +55,20 @@ void pstack_maybe(void)
void diediedie(void)
{
std::cerr << "\nAborting " PACKAGE
" due to a fatal error.\nPlease report this to "
PACKAGE_BUGREPORT << "\n\n";
pstack(STDERR_FILENO);
extern std::string version_text;
std::cerr << "\nVersion information:\n" << version_text;
if (signum != SIGABRT)
abort();
static bool print_trace = true;
if (print_trace) {
if (signum)
std::cerr << "\nCaught signal " << signum;
std::cerr << "\nAborting " PACKAGE_TARNAME
" due to a fatal error.\nPlease report this to "
PACKAGE_BUGREPORT << "\n\n*** Stack trace:\n";
pstack(STDERR_FILENO);
extern std::string version_text;
std::cerr << "\n*** Version information:\n" << version_text;
print_trace = false;
}
abort();
}
void handle_unexpected(void)
@ -74,7 +80,6 @@ void handle_unexpected(void)
// this may not give us anything useful, but we can try...
void handle_signal(int s)
{
std::cerr << "Caught signal " << s;
signum = s;
diediedie();
}

Wyświetl plik

@ -2,6 +2,12 @@
#include <iostream>
#include <fstream>
#include <string>
#include <FL/Fl_Preferences.H>
#include "main.h"
#include "globals.h"
#include "status.h"
#include "configuration.h"
@ -24,12 +30,12 @@
#include "rigsupport.h"
extern void startup_modem(modem *m);
extern Fl_Double_Window *dlgViewer;
extern void openViewer();
#include "Viewer.h"
#define STATUS_FILENAME "status"
status progStatus = {
(int)MODE_BPSK31, // trx_mode lastmode;
MODE_BPSK31, // trx_mode lastmode;
50, // int mainX;
50, // int mainY;
WNOM, // int mainW;
@ -58,16 +64,9 @@ status progStatus = {
false, // bool scopeVisible;
50, // int scopeW;
50, // int scopeH;
false // bool bLastStateRead;
};
void status::saveModeState(trx_mode m)
{
lastmode = (int)m;
}
false // bool bLastStateRead;
};
void status::saveLastState()
{
@ -76,137 +75,135 @@ void status::saveLastState()
mainW = fl_digi_main->w();
mainH = fl_digi_main->h();
RxTextHeight = ReceiveText->h();
rigShown = false;
rigX = 0;
rigY = 0;
carrier = wf->Carrier();
mag = wf->Mag();
speed = wf->Speed();
reflevel = progdefaults.wfRefLevel;
ampspan = progdefaults.wfAmpSpan;
LOGenabled = false;
Fl_Menu_Item *mnulogging = getMenuItem("Log File");
if (mnulogging)
LOGenabled = mnulogging->value();
else
LOGenabled = false;
if (dlgViewer) {
if (dlgViewer->visible()) {
VIEWERxpos = dlgViewer->x();
VIEWERypos = dlgViewer->y();
VIEWERvisible = true;
} else
VIEWERvisible = false;
VIEWERvisible = false;
if (dlgViewer && dlgViewer->visible()) {
VIEWERxpos = dlgViewer->x();
VIEWERypos = dlgViewer->y();
VIEWERvisible = true;
}
if (rigcontrol)
if (rigcontrol->visible()) {
rigShown = rigcontrol->visible();
rigX = rigcontrol->x();
rigY = rigcontrol->y();
}
if (scopeview) {
if (scopeview->visible())
scopeVisible = true;
else
scopeVisible = false;
rigShown = false;
if (rigcontrol && rigcontrol->visible()) {
rigX = rigcontrol->x();
rigY = rigcontrol->y();
rigShown = true;
}
scopeVisible = false;
if (scopeview && scopeview->visible()) {
scopeVisible = true;
scopeX = scopeview->x();
scopeY = scopeview->y();
scopeW = scopeview->w();
scopeH = scopeview->h();
}
string str = PACKAGE_NAME;
str.append(" ");
str.append(PACKAGE_VERSION);
string deffname = HomeDir;
deffname.append("fldigi.status");
ofstream deffile(deffname.c_str(), ios::out);
Fl_Preferences spref(string(HomeDir).append(STATUS_FILENAME).c_str(), "w1hkj.com", 0);
deffile << str.c_str() << endl;
deffile << lastmode << endl;
deffile << mainX << endl;
deffile << mainY << endl;
deffile << mainW << endl;
deffile << mainH << endl;
deffile << rigShown << endl;
deffile << rigX << endl;
deffile << rigY << endl;
deffile << RxTextHeight << endl;
deffile << carrier << endl;
deffile << mag << endl;
deffile << speed << endl;
deffile << reflevel << endl;
deffile << ampspan << endl;
deffile << VIEWERnchars << endl;
deffile << VIEWERxpos << endl;
deffile << VIEWERypos << endl;
deffile << VIEWERvisible << endl;
deffile << LOGenabled << endl;
deffile << sldrSquelchValue << endl;
deffile << afconoff << endl;
deffile << sqlonoff << endl;
deffile << RcvMixer << endl;
deffile << XmtMixer << endl;
deffile << scopeX << endl;
deffile << scopeY << endl;
deffile << scopeVisible << endl;
deffile << scopeW << endl;
deffile << scopeH << endl;
deffile.close();
spref.set("version", PACKAGE_VERSION);
spref.set("mode", (int)lastmode);
spref.set("squelch_enabled", sqlonoff);
spref.set("squelch_level", sldrSquelchValue);
spref.set("afc_enabled", afconoff);
spref.set("rx_mixer_level", RcvMixer);
spref.set("tx_mixer_level", XmtMixer);
spref.set("rx_text_height", RxTextHeight);
spref.set("log_enabled", LOGenabled);
spref.set("wf_carrier", carrier);
spref.set("wf_mag", mag);
spref.set("wf_speed", speed);
spref.set("wf_reflevel", reflevel);
spref.set("wf_ampspan", ampspan);
spref.set("main_x", mainX);
spref.set("main_y", mainY);
spref.set("main_w", mainW);
spref.set("main_h", mainH);
spref.set("rigctl_visible", rigShown);
spref.set("rigctl_x", rigX);
spref.set("rigctl_y", rigY);
spref.set("viewer_visible", VIEWERvisible);
spref.set("viewer_x", static_cast<int>(VIEWERxpos));
spref.set("viewer_y", static_cast<int>(VIEWERypos));
spref.set("viewer_nchars", static_cast<int>(VIEWERnchars));
spref.set("scope_visible", scopeVisible);
spref.set("scope_x", scopeX);
spref.set("scope_y", scopeY);
spref.set("scope_w", scopeW);
spref.set("scope_h", scopeH);
}
void status::loadLastState()
{
char line[255];
string str = PACKAGE_NAME;
str.append(" ");
str.append(PACKAGE_VERSION);
string deffname = HomeDir;
deffname.append("fldigi.status");
ifstream deffile(deffname.c_str(), ios::in);
if (deffile) {
deffile.getline(line, 255);
if (str == line) {
deffile >> lastmode;
deffile >> mainX;
deffile >> mainY;
deffile >> mainW;
deffile >> mainH;
deffile >> rigShown;
deffile >> rigX;
deffile >> rigY;
deffile >> RxTextHeight;
deffile >> carrier;
deffile >> mag;
deffile >> speed;
deffile >> reflevel;
deffile >> ampspan;
deffile >> VIEWERnchars;
deffile >> VIEWERxpos;
deffile >> VIEWERypos;
deffile >> VIEWERvisible;
deffile >> LOGenabled;
deffile >> sldrSquelchValue;
deffile >> afconoff;
deffile >> sqlonoff;
deffile >> RcvMixer;
deffile >> XmtMixer;
deffile >> scopeX;
deffile >> scopeY;
deffile >> scopeVisible;
deffile >> scopeW;
deffile >> scopeH;
deffile.close();
progdefaults.wfRefLevel = reflevel;
progdefaults.wfAmpSpan = ampspan;
bLastStateRead = true;
}
Fl_Preferences spref(string(HomeDir).append(STATUS_FILENAME).c_str(), "w1hkj.com", 0);
char version[64]; version[sizeof(version)-1] = '\0';
bLastStateRead = spref.get("version", version, "", sizeof(version)-1);
// Skip loading the rest of the status variables if we didn't read a
// version name/value pair; also clear everything to avoid creating
// entries out of existing file contents.
if (!bLastStateRead) {
while (spref.entries())
spref.deleteEntry(spref.entry(0));
return;
}
int i;
spref.get("mode", i, i); lastmode = (trx_mode) i;
spref.get("squelch_enabled", i, i); sqlonoff = i;
spref.get("squelch_level", sldrSquelchValue, sldrSquelchValue);
spref.get("afc_enabled", i, i); afconoff = i;
spref.get("rx_mixer_level", RcvMixer, RcvMixer);
spref.get("tx_mixer_level", XmtMixer, XmtMixer);
spref.get("rx_text_height", RxTextHeight, RxTextHeight);
spref.get("log_enabled", i, i); LOGenabled = i;
spref.get("wf_carrier", carrier, carrier);
spref.get("wf_mag", mag, mag);
spref.get("wf_speed", speed, speed);
spref.get("wf_reflevel", reflevel, reflevel);
progdefaults.wfRefLevel = reflevel;
spref.get("wf_ampspan", ampspan, ampspan);
progdefaults.wfAmpSpan = ampspan;
spref.get("main_x", mainX, mainX);
spref.get("main_y", mainY, mainY);
spref.get("main_w", mainW, mainW);
spref.get("main_h", mainH, mainH);
spref.get("rigctl_visible", i, i); rigShown = i;
spref.get("rigctl_x", rigX, rigX);
spref.get("rigctl_y", rigY, rigY);
spref.get("viewer_visible", i, i); VIEWERvisible = i;
spref.get("viewer_x", i, i); VIEWERxpos = i;
spref.get("viewer_y", i, i); VIEWERypos = i;
spref.get("viewer_nchars", i, i); VIEWERnchars = i;
spref.get("scope_visible", i, i); scopeVisible = i;
spref.get("scope_x", scopeX, scopeX);
spref.get("scope_y", scopeY, scopeY);
spref.get("scope_w", scopeW, scopeW);
spref.get("scope_h", scopeH, scopeH);
}
void status::initLastState()
@ -214,7 +211,7 @@ void status::initLastState()
if (!bLastStateRead)
loadLastState();
init_modem((trx_mode)lastmode);
init_modem(lastmode);
while (!active_modem) MilliSleep(100);

Wyświetl plik

@ -47,10 +47,13 @@
#endif
#include <math.h>
#if HAVE_DLOPEN
# include <dlfcn.h>
#endif
#include "sound.h"
#include "configuration.h"
#include "status.h"
#include <FL/Fl.H>
#include "fileselect.h"
#include "timeops.h"
@ -98,20 +101,25 @@ void SoundBase::get_file_params(const char* def_fname, const char** fname, int*
if (format_supported(SF_FORMAT_FLAC | SF_FORMAT_PCM_16))
filters += "Free Lossless Audio Codec\t*.flac";
int fsel;
if (strstr(def_fname, "playback"))
*fname = file_select("Audio file", filters.c_str(), def_fname);
*fname = file_select("Audio file", filters.c_str(), def_fname, &fsel);
else
*fname = file_saveas("Audio file", filters.c_str(), def_fname);
*fname = file_saveas("Audio file", filters.c_str(), def_fname, &fsel);
if (!*fname)
return;
char* suffix = strrchr(*fname, '.');
if (suffix && !strcasecmp(suffix, ".flac"))
*format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16;
else if (suffix && !strcasecmp(suffix, ".au"))
*format = SF_FORMAT_AU | SF_FORMAT_FLOAT | SF_ENDIAN_CPU;
else
switch (fsel) {
case 0:
*format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
break;
case 1:
*format = SF_FORMAT_AU | SF_FORMAT_FLOAT | SF_ENDIAN_CPU;
break;
case 2:
*format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16;
break;
}
}
int SoundBase::Capture(bool val)
@ -129,7 +137,7 @@ int SoundBase::Capture(bool val)
const char* fname;
int format;
get_file_params("./capture.wav", &fname, &format);
get_file_params("capture.wav", &fname, &format);
if (!fname)
return 0;
@ -161,7 +169,7 @@ int SoundBase::Playback(bool val)
}
const char* fname;
int format;
get_file_params("./playback.wav", &fname, &format);
get_file_params("playback.wav", &fname, &format);
if (!fname)
return 0;
@ -190,7 +198,7 @@ int SoundBase::Generate(bool val)
const char* fname;
int format;
get_file_params("./generate.wav", &fname, &format);
get_file_params("generate.wav", &fname, &format);
if (!fname)
return 0;
@ -668,6 +676,8 @@ void SoundPort::initialize(void)
if (pa_init)
return;
init_hostapi_ext();
int err;
if ((err = Pa_Initialize()) != paNoError)
@ -708,6 +718,7 @@ SoundPort::SoundPort(const char *in_dev, const char *out_dev)
sd[0].dev_sample_rate = sd[1].dev_sample_rate = 0;
sd[0].state = sd[1].state = spa_continue;
sd[0].rb = sd[1].rb = 0;
sd[0].advance = sd[1].advance = 0;
sem_t** sems[] = { &sd[0].rwsem, &sd[0].csem, &sd[1].rwsem, &sd[1].csem };
for (size_t i = 0; i < sizeof(sems)/sizeof(*sems); i++) {
@ -717,7 +728,6 @@ SoundPort::SoundPort(const char *in_dev, const char *out_dev)
}
try {
rx_src_data = new SRC_DATA;
tx_src_data = new SRC_DATA;
}
catch (const std::bad_alloc& e) {
@ -780,7 +790,7 @@ int SoundPort::Open(int mode, int freq)
start_stream(i);
}
else if (old_sample_rate != freq)
else
src_data_reset(m[i]);
}
@ -879,7 +889,13 @@ size_t SoundPort::Read(double *buf, size_t count)
}
#endif
size_t maxframes = (size_t)floor((sd[0].rb->length() / CHANNELS) * rx_src_data->src_ratio);
if (rxppm != progdefaults.RX_corr) {
rxppm = progdefaults.RX_corr;
sd[0].src_ratio = req_sample_rate / (sd[0].dev_sample_rate * (1.0 + rxppm / 1e6));
src_set_ratio(rx_src_state, sd[0].src_ratio);
}
size_t maxframes = (size_t)floor((sd[0].rb->length() / CHANNELS) * sd[0].src_ratio);
if (unlikely(count > maxframes)) {
size_t n = 0;
while (count > maxframes) {
@ -892,38 +908,36 @@ size_t SoundPort::Read(double *buf, size_t count)
return n;
}
// new sample count, taking into account the samplerate ratio
size_t ncount = (size_t)floor(count / rx_src_data->src_ratio);
// wait for data
bool timeout = false;
WAIT_FOR_COND( (sd[0].rb->read_space() >= CHANNELS * ncount), sd[0].rwsem,
(MAX(1.0, 2 * CHANNELS * ncount / sd[0].dev_sample_rate)) );
if (timeout)
throw SndException(ETIMEDOUT);
// copy to fbuf if the data is not contiguous inside the ringbuffer
float* rbuf = 0;
bool rbadv = true;
ringbuffer<float>::vector_type vec[2];
sd[0].rb->get_rv(vec);
if (likely(vec[0].len >= CHANNELS * ncount))
rbuf = vec[0].buf;
else { // copy
sd[0].rb->read(fbuf, CHANNELS * ncount);
rbuf = fbuf;
rbadv = false;
}
// resample
if (req_sample_rate != sd[0].dev_sample_rate || progdefaults.RX_corr != 0) {
resample(1 << O_RDONLY, rbuf, snd_buffer, ncount, count);
rbuf = rx_src_data->data_out;
count = rx_src_data->output_frames_gen;
}
// if we did a no-copy read we must advance the read pointer
if (rbadv)
sd[0].rb->read_advance(CHANNELS * ncount);
float* rbuf = fbuf;
if (req_sample_rate != sd[0].dev_sample_rate || rxppm != 0) {
long r;
size_t n = 0;
sd[0].blocksize = SCBLOCKSIZE;
while (n < count) {
if ((r = src_callback_read(rx_src_state, sd[0].src_ratio, count - n, rbuf + n*CHANNELS)) == 0)
return n;
n += r;
}
}
else {
bool timeout = false;
WAIT_FOR_COND( (sd[0].rb->read_space() >= count * CHANNELS / sd[0].src_ratio), sd[0].rwsem,
(MAX(1.0, 2 * CHANNELS * count / sd->dev_sample_rate)) );
if (timeout)
throw SndException(ETIMEDOUT);
ringbuffer<float>::vector_type vec[2];
sd[0].rb->get_rv(vec);
if (vec[0].len >= count * CHANNELS) {
rbuf = vec[0].buf;
sd[0].advance = vec[0].len;
}
else
sd[0].rb->read(fbuf, count * CHANNELS);
}
if (sd[0].advance) {
sd[0].rb->read_advance(sd[0].advance);
sd[0].advance = 0;
}
// deinterleave first channel into buf
for (size_t i = 0; i < count; i++)
@ -995,7 +1009,21 @@ size_t SoundPort::resample_write(float* buf, size_t count)
wbuf = vec[0].buf; // direct write in the rb
else
wbuf = src_buffer;
resample(1 << O_WRONLY, buf, wbuf, count);
if (txppm != progdefaults.TX_corr) {
txppm = progdefaults.TX_corr;
tx_src_data->src_ratio = sd[1].dev_sample_rate * (1.0 + txppm / 1e6) / req_sample_rate;
src_set_ratio(tx_src_state, tx_src_data->src_ratio);
}
tx_src_data->data_in = buf;
tx_src_data->input_frames = count;
tx_src_data->data_out = wbuf;
tx_src_data->output_frames = (wbuf == vec[0].buf ? vec[0].len : SND_BUF_LEN);
tx_src_data->end_of_input = 0;
int r;
if ((r = src_process(tx_src_state, tx_src_data)) != 0)
throw SndException(src_strerror(r));
count = tx_src_data->output_frames_gen;
if (wbuf == vec[0].buf) { // advance write pointer and return
sd[1].rb->write_advance(CHANNELS * count);
@ -1044,10 +1072,11 @@ void SoundPort::src_data_reset(int mode)
if (mode & 1 << O_RDONLY) {
if (rx_src_state)
src_delete(rx_src_state);
rx_src_state = src_new(progdefaults.sample_converter, CHANNELS, &err);
rx_src_state = src_callback_new(src_read_cb, progdefaults.sample_converter,
CHANNELS, &err, &sd[0]);
if (!rx_src_state)
throw SndException(src_strerror(err));
rx_src_data->src_ratio = req_sample_rate / (sd[0].dev_sample_rate * (1.0 + rxppm / 1e6));
sd[0].src_ratio = req_sample_rate / (sd[0].dev_sample_rate * (1.0 + rxppm / 1e6));
rbsize = ceil2((unsigned)(2 * CHANNELS * SCBLOCKSIZE *
MAX(req_sample_rate, sd[0].dev_sample_rate) /
@ -1085,42 +1114,30 @@ void SoundPort::src_data_reset(int mode)
}
}
void SoundPort::resample(int mode, float* inbuf, float* outbuf, size_t count, size_t max)
long SoundPort::src_read_cb(void* arg, float** data)
{
int r;
struct stream_data* sd = reinterpret_cast<stream_data*>(arg);
if (mode & 1 << O_RDONLY) {
if (rxppm != progdefaults.RX_corr) {
rxppm = progdefaults.RX_corr;
rx_src_data->src_ratio = req_sample_rate / (sd[0].dev_sample_rate * (1.0 + rxppm / 1e6));
src_set_ratio(rx_src_state, rx_src_data->src_ratio);
}
rx_src_data->data_in = inbuf;
rx_src_data->input_frames = count;
rx_src_data->data_out = outbuf;
rx_src_data->output_frames = max ? max : SND_BUF_LEN;
rx_src_data->end_of_input = 0;
if ((r = src_process(rx_src_state, rx_src_data)) != 0)
throw SndException(src_strerror(r));
// advance read pointer for previous read
if (sd->advance) {
sd->rb->read_advance(sd->advance);
sd->advance = 0;
}
else if (mode & 1 << O_WRONLY) {
if (txppm != progdefaults.TX_corr) {
txppm = progdefaults.TX_corr;
tx_src_data->src_ratio = sd[1].dev_sample_rate * (1.0 + txppm / 1e6) / req_sample_rate;
src_set_ratio(tx_src_state, tx_src_data->src_ratio);
}
tx_src_data->data_in = inbuf;
tx_src_data->input_frames = count;
tx_src_data->data_out = outbuf;
tx_src_data->output_frames = max ? max : SND_BUF_LEN;
tx_src_data->end_of_input = 0;
// wait for data
bool timeout = false;
WAIT_FOR_COND( (sd->rb->read_space() >= CHANNELS * SCBLOCKSIZE), sd->rwsem,
(MAX(1.0, 2 * CHANNELS * SCBLOCKSIZE / sd->dev_sample_rate)) );
if (timeout)
return 0;
if ((r = src_process(tx_src_state, tx_src_data)) != 0)
throw SndException(src_strerror(r));
}
ringbuffer<float>::vector_type vec[2];
sd->rb->get_rv(vec);
*data = vec[0].buf;
sd->advance = vec[0].len;
return vec[0].len / CHANNELS;
}
void SoundPort::init_stream(unsigned dir)
@ -1384,6 +1401,21 @@ void SoundPort::pa_perror(int err, const char* str)
}
}
void SoundPort::init_hostapi_ext(void)
{
#if HAVE_DLOPEN
void* handle = dlopen(NULL, RTLD_LAZY);
if (!handle)
return;
PaError (*set_jack_client_name)(const char*);
char* err = dlerror();
set_jack_client_name = (PaError (*)(const char*))dlsym(handle, "PaJack_SetClientName");
if (!(err = dlerror()))
set_jack_client_name(PACKAGE_TARNAME);
#endif
}
#endif // USE_PORTAUDIO
@ -1392,10 +1424,12 @@ void SoundPort::pa_perror(int err, const char* str)
SoundPulse::SoundPulse(const char *dev)
: fbuf(0)
{
stream[0] = stream[1] = 0;
sd[0].stream = sd[1].stream = 0;
sd[0].dir = PA_STREAM_RECORD; sd[1].dir = PA_STREAM_PLAYBACK;
sd[0].stream_params.format = sd[1].stream_params.format = PA_SAMPLE_FLOAT32LE;
sd[0].stream_params.channels = sd[1].stream_params.channels = CHANNELS;
try {
rx_src_data = new SRC_DATA;
tx_src_data = new SRC_DATA;
}
catch (const std::bad_alloc& e) {
@ -1404,9 +1438,9 @@ SoundPulse::SoundPulse(const char *dev)
}
try {
snd_buffer = new float[2 * SND_BUF_LEN];
src_buffer = new float[2 * SND_BUF_LEN];
fbuf = new float[2 * SND_BUF_LEN];
snd_buffer = new float[CHANNELS * SND_BUF_LEN];
src_buffer = new float[CHANNELS * SND_BUF_LEN];
fbuf = new float[CHANNELS * SND_BUF_LEN];
}
catch (const std::bad_alloc& e) {
cerr << "Cannot allocate libsamplerate buffers\n";
@ -1422,51 +1456,27 @@ SoundPulse::~SoundPulse()
int SoundPulse::Open(int mode, int freq)
{
int old_sample_rate = sample_frequency;
dev_sample_rate[0] = (progdefaults.in_sample_rate > 1 ?
progdefaults.in_sample_rate : 48000);
dev_sample_rate[1] = (progdefaults.out_sample_rate > 1 ?
progdefaults.out_sample_rate : 48000);
sample_frequency = freq;
if (stream[0] && stream[1]) {
if (sample_frequency != old_sample_rate) {
src_data_reset(1 << O_RDONLY | 1 << O_WRONLY);
return 0;
}
}
else
Close();
const char* server = (progdefaults.PulseServer.length() ?
progdefaults.PulseServer.c_str() : NULL);
char sname[32];
int err;
stream_params.format = PA_SAMPLE_FLOAT32LE;
stream_params.channels = 2;
for (int i = 0; i < 2; i++) {
src_data_reset(1 << O_RDONLY | 1 << O_WRONLY);
stream_params.rate = dev_sample_rate[0];
snprintf(sname, sizeof(sname), "capture (%u)", getpid());
if (!stream[0]) {
stream[0] = pa_simple_new(server, PACKAGE_NAME, PA_STREAM_RECORD, NULL,
sname, &stream_params, NULL, NULL, &err);
if (!stream[0])
if ((unsigned)freq != sd[i].stream_params.rate)
Close(i);
if (sd[i].stream)
continue;
sd[i].stream_params.rate = freq;
snprintf(sname, sizeof(sname), "%s (%u)", (i ? "playback" : "capture"), getpid());
sd[i].stream = pa_simple_new(server, PACKAGE_TARNAME, sd[i].dir, NULL,
sname, &sd[i].stream_params, NULL, NULL, &err);
if (!sd[i].stream)
throw SndPulseException(err);
}
stream_params.rate = dev_sample_rate[1];
snprintf(sname, sizeof(sname), "playback (%u)", getpid());
if (!stream[1]) {
stream[1] = pa_simple_new(server, PACKAGE_NAME, PA_STREAM_PLAYBACK, NULL,
sname, &stream_params, NULL, NULL, &err);
if (!stream[1])
throw SndPulseException(err);
}
src_data_reset(1 << O_RDONLY | 1 << O_WRONLY);
return 0;
}
@ -1481,7 +1491,7 @@ void SoundPulse::Close(unsigned dir)
start = end = dir;
for (unsigned i = start; i <= end; i++) {
if (stream[i]) {
if (sd[i].stream) {
flush(i);
Abort(i);
}
@ -1499,9 +1509,9 @@ void SoundPulse::Abort(unsigned dir)
start = end = dir;
for (unsigned i = start; i <= end; i++) {
if (stream[i]) {
pa_simple_free(stream[i]);
stream[i] = 0;
if (sd[i].stream) {
pa_simple_free(sd[i].stream);
sd[i].stream = 0;
}
}
@ -1519,9 +1529,9 @@ void SoundPulse::flush(unsigned dir)
int err = PA_OK;
for (unsigned i = start; i <= end; i++) {
if (!stream[i])
if (!sd[i].stream)
continue;
pa_simple_drain(stream[i], &err);
pa_simple_drain(sd[i].stream, &err);
if (err != PA_OK)
cerr << pa_strerror(err) << '\n';
}
@ -1535,20 +1545,9 @@ size_t SoundPulse::Write(double* buf, size_t count)
#endif
for (size_t i = 0; i < count; i++)
fbuf[2*i] = fbuf[2*i + 1] = buf[i];
fbuf[CHANNELS * i] = fbuf[CHANNELS * i + 1] = buf[i];
float *wbuf = fbuf;
if (sample_frequency != dev_sample_rate[1] || progdefaults.TX_corr != 0) {
resample(1 << O_WRONLY, wbuf, count);
wbuf = tx_src_data->data_out;
count = tx_src_data->output_frames_gen;
}
int err;
if (pa_simple_write(stream[1], wbuf, count * sizeof(double), &err) == -1)
throw SndPulseException(err);
return count;
return resample_write(fbuf, count);
}
size_t SoundPulse::Write_stereo(double* bufleft, double* bufright, size_t count)
@ -1559,34 +1558,58 @@ size_t SoundPulse::Write_stereo(double* bufleft, double* bufright, size_t count)
#endif
for (size_t i = 0; i < count; i++) {
fbuf[2*i] = bufleft[i];
fbuf[2*i + 1] = bufright[i];
fbuf[CHANNELS * i] = bufleft[i];
fbuf[CHANNELS * i + 1] = bufright[i];
}
float *wbuf = fbuf;
if (sample_frequency != dev_sample_rate[1] || progdefaults.TX_corr != 0) {
resample(1 << O_WRONLY, wbuf, count);
return resample_write(fbuf, count);
}
size_t SoundPulse::resample_write(float* buf, size_t count)
{
int err;
float *wbuf = buf;
if (progdefaults.TX_corr != 0) {
if (txppm != progdefaults.TX_corr) {
txppm = progdefaults.TX_corr;
tx_src_data->src_ratio = 1.0 + txppm / 1e6;
src_set_ratio(tx_src_state, tx_src_data->src_ratio);
}
tx_src_data->data_in = wbuf;
tx_src_data->input_frames = count;
tx_src_data->data_out = src_buffer;
tx_src_data->output_frames = SND_BUF_LEN;
tx_src_data->end_of_input = 0;
if ((err = src_process(tx_src_state, tx_src_data)) != 0)
throw SndException(src_strerror(err));
wbuf = tx_src_data->data_out;
count = tx_src_data->output_frames_gen;
}
int err;
if (pa_simple_write(stream[1], wbuf, count * sizeof(double), &err) == -1)
if (pa_simple_write(sd[1].stream, wbuf, count * CHANNELS * sizeof(float), &err) == -1)
throw SndPulseException(err);
return count;
}
size_t SoundPulse::Read(double *buf, size_t count)
long SoundPulse::src_read_cb(void* arg, float** data)
{
size_t ncount = (size_t)MIN(SND_BUF_LEN, floor(count / rx_src_data->src_ratio));
if (count == 1 && ncount == 0)
ncount = 1;
SoundPulse* p = reinterpret_cast<SoundPulse*>(arg);
int err;
if (pa_simple_read(stream[0], fbuf, sizeof(double) * ncount, &err) == -1)
throw SndPulseException(err);
if (pa_simple_read(p->sd[0].stream, p->snd_buffer, CHANNELS * sizeof(float) * p->sd[0].blocksize, &err) == -1) {
cerr << "SoundPulse::pa_simple_read error: " << pa_strerror(err) << '\n';
return 0;
}
*data = p->snd_buffer;
return p->sd[0].blocksize;
}
size_t SoundPulse::Read(double *buf, size_t count)
{
#if USE_SNDFILE
if (playback) {
read_file(ifPlayback, buf, count);
@ -1599,15 +1622,29 @@ size_t SoundPulse::Read(double *buf, size_t count)
}
#endif
float *rbuf = fbuf;
if (sample_frequency != dev_sample_rate[0] || progdefaults.RX_corr != 0) {
resample(1 << O_RDONLY, rbuf, ncount, count);
rbuf = rx_src_data->data_out;
count = rx_src_data->output_frames_gen;
if (progdefaults.RX_corr != 0) {
if (rxppm != progdefaults.RX_corr) {
rxppm = progdefaults.RX_corr;
sd[0].src_ratio = 1.0 / (1.0 + rxppm / 1e6);
src_set_ratio(rx_src_state, sd[0].src_ratio);
}
long r;
size_t n = 0;
sd[0].blocksize = SCBLOCKSIZE;
while (n < count) {
if ((r = src_callback_read(rx_src_state, sd[0].src_ratio, count - n, fbuf + n*CHANNELS)) == 0)
return n;
n += r;
}
}
else {
int err;
if (pa_simple_read(sd[0].stream, fbuf, CHANNELS * sizeof(float) * count, &err) == -1)
throw SndPulseException(err);
}
for (size_t i = 0; i < count; i++)
buf[i] = rbuf[2*i];
buf[i] = fbuf[CHANNELS * i];
#if USE_SNDFILE
if (capture)
@ -1623,56 +1660,19 @@ void SoundPulse::src_data_reset(int mode)
if (mode & 1 << O_RDONLY) {
if (rx_src_state)
src_delete(rx_src_state);
rx_src_state = src_new(progdefaults.sample_converter, stream_params.channels, &err);
rx_src_state = src_callback_new(src_read_cb, progdefaults.sample_converter,
sd[0].stream_params.channels, &err, this);
if (!rx_src_state)
throw SndException(src_strerror(err));
rx_src_data->src_ratio = sample_frequency / (dev_sample_rate[0] * (1.0 + rxppm / 1e6));
sd[0].src_ratio = 1.0 / (1.0 + rxppm / 1e6);
}
if (mode & 1 << O_WRONLY) {
if (tx_src_state)
src_delete(tx_src_state);
tx_src_state = src_new(progdefaults.sample_converter, stream_params.channels, &err);
tx_src_state = src_new(progdefaults.sample_converter, sd[1].stream_params.channels, &err);
if (!tx_src_state)
throw SndException(src_strerror(err));
tx_src_data->src_ratio = dev_sample_rate[1] * (1.0 + txppm / 1e6) / sample_frequency;
}
}
void SoundPulse::resample(int mode, float *buf, size_t count, size_t max)
{
int r;
if (mode & 1 << O_RDONLY) {
if (rxppm != progdefaults.RX_corr) {
rxppm = progdefaults.RX_corr;
rx_src_data->src_ratio = sample_frequency / (dev_sample_rate[0] * (1.0 + rxppm / 1e6));
src_set_ratio(rx_src_state, rx_src_data->src_ratio);
}
rx_src_data->data_in = buf;
rx_src_data->input_frames = count;
rx_src_data->data_out = snd_buffer;
rx_src_data->output_frames = max ? max : SND_BUF_LEN;
rx_src_data->end_of_input = 0;
if ((r = src_process(rx_src_state, rx_src_data)) != 0)
throw SndException(src_strerror(r));
}
else if (mode & 1 << O_WRONLY) {
if (txppm != progdefaults.TX_corr) {
txppm = progdefaults.TX_corr;
tx_src_data->src_ratio = dev_sample_rate[1] * (1.0 + txppm / 1e6) / sample_frequency;
src_set_ratio(tx_src_state, tx_src_data->src_ratio);
}
tx_src_data->data_in = buf;
tx_src_data->input_frames = count;
tx_src_data->data_out = src_buffer;
tx_src_data->output_frames = max ? max : SND_BUF_LEN;
tx_src_data->end_of_input = 0;
if ((r = src_process(tx_src_state, tx_src_data)) != 0)
throw SndException(src_strerror(r));
tx_src_data->src_ratio = 1.0 + txppm / 1e6;
}
}

Wyświetl plik

@ -317,8 +317,6 @@ void sound_update(unsigned idx)
break;
case SND_IDX_PULSE:
inpPulseServer->activate();
menuInSampleRate->activate();
menuOutSampleRate->activate();
scDevice[0] = scDevice[1] = inpPulseServer->value();
break;
case SND_IDX_NULL:

Wyświetl plik

@ -35,6 +35,12 @@ modem *qpsk125_modem = 0;
modem *qpsk250_modem = 0;
modem *olivia_modem = 0;
modem *rtty_modem = 0;
modem *dex4_modem = 0;
modem *dex5_modem = 0;
modem *dex8_modem = 0;
modem *dex11_modem = 0;
modem *dex16_modem = 0;
modem *dex22_modem = 0;
modem *dominoex4_modem = 0;
modem *dominoex5_modem = 0;
modem *dominoex8_modem = 0;