kopia lustrzana https://github.com/jamescoxon/dl-fldigi
Enable concurrent RSID decoding
* Change Sound*::Read methods to float * Enable RSID upsampling for 8 KHz modems * Add main.{get,set,toggle}_rsid XML-RPC methods * Add option to disable RSID decoding on reception * RSID may be enabled during transmit or tunepull/2/head
rodzic
4de96c9b34
commit
b09cea25ff
|
@ -1945,6 +1945,12 @@ Fl_Check_Button *chkRSidNotifyOnly=(Fl_Check_Button *)0;
|
|||
static void cb_chkRSidNotifyOnly(Fl_Check_Button* o, void*) {
|
||||
progdefaults.rsid_notify_only = o->value();
|
||||
notify_create_rsid_event(progdefaults.rsid_notify_only);
|
||||
if (progdefaults.rsid_notify_only) {
|
||||
chkRSidAutoDisable->value(0);
|
||||
chkRSidAutoDisable->deactivate();
|
||||
}
|
||||
else
|
||||
chkRSidAutoDisable->activate();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
|
@ -1955,6 +1961,13 @@ static void cb_chkRSidMark(Fl_Check_Button* o, void*) {
|
|||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Check_Button *chkRSidAutoDisable=(Fl_Check_Button *)0;
|
||||
|
||||
static void cb_chkRSidAutoDisable(Fl_Check_Button* o, void*) {
|
||||
progdefaults.rsid_auto_disable = o->value();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Group *tabMisc=(Fl_Group *)0;
|
||||
|
||||
Fl_Tabs *tabsMisc=(Fl_Tabs *)0;
|
||||
|
@ -4272,7 +4285,7 @@ ll with your audio device."));
|
|||
} // Fl_Value_Slider* sldrCWIDwpm
|
||||
sld->end();
|
||||
} // Fl_Group* sld
|
||||
{ Fl_Group* o = new Fl_Group(5, 218, 490, 94, _("Reed-Solomon ID"));
|
||||
{ Fl_Group* o = new Fl_Group(5, 218, 490, 120, _("Reed-Solomon ID"));
|
||||
o->box(FL_ENGRAVED_FRAME);
|
||||
o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
|
||||
{ Fl_Check_Button* o = chkTransmitRSid = new Fl_Check_Button(15, 246, 165, 20, _("Transmit mode RSID"));
|
||||
|
@ -4300,6 +4313,14 @@ d frequency"));
|
|||
chkRSidMark->callback((Fl_Callback*)cb_chkRSidMark);
|
||||
chkRSidMark->value(progdefaults.rsid_mark);
|
||||
} // Fl_Check_Button* chkRSidMark
|
||||
{ chkRSidAutoDisable = new Fl_Check_Button(15, 306, 200, 20, _("Reception disables detector"));
|
||||
chkRSidAutoDisable->tooltip(_("Disable further detection when RSID is received"));
|
||||
chkRSidAutoDisable->down_box(FL_DOWN_BOX);
|
||||
chkRSidAutoDisable->callback((Fl_Callback*)cb_chkRSidAutoDisable);
|
||||
if (progdefaults.rsid_notify_only) progdefaults.rsid_auto_disable = false;
|
||||
chkRSidAutoDisable->value(progdefaults.rsid_auto_disable);
|
||||
if (progdefaults.rsid_notify_only) chkRSidAutoDisable->deactivate();
|
||||
} // Fl_Check_Button* chkRSidAutoDisable
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
tabID->end();
|
||||
|
|
|
@ -82,7 +82,7 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600
|
|||
code {} {}
|
||||
Fl_Window {} {
|
||||
label {Fldigi configuration} open
|
||||
xywh {646 121 500 400} type Double color 45 selection_color 51 labelsize 18 align 80 visible
|
||||
xywh {646 129 500 400} type Double color 45 selection_color 51 labelsize 18 align 80 visible
|
||||
} {
|
||||
Fl_Tabs tabsConfigure {open
|
||||
xywh {0 0 517 372} color 50 selection_color 50
|
||||
|
@ -2369,7 +2369,7 @@ progdefaults.changed = true;}
|
|||
}
|
||||
Fl_Group {} {
|
||||
label {Reed-Solomon ID} open
|
||||
xywh {5 218 490 94} box ENGRAVED_FRAME align 21
|
||||
xywh {5 218 490 120} box ENGRAVED_FRAME align 21
|
||||
} {
|
||||
Fl_Check_Button chkTransmitRSid {
|
||||
label {Transmit mode RSID}
|
||||
|
@ -2390,6 +2390,12 @@ OFF - limit search to +/- 200 Hz} xywh {215 246 270 20} down_box DOWN_BOX
|
|||
label {Notifications only}
|
||||
callback {progdefaults.rsid_notify_only = o->value();
|
||||
notify_create_rsid_event(progdefaults.rsid_notify_only);
|
||||
if (progdefaults.rsid_notify_only) {
|
||||
chkRSidAutoDisable->value(0);
|
||||
chkRSidAutoDisable->deactivate();
|
||||
}
|
||||
else
|
||||
chkRSidAutoDisable->activate();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Check this to be notified when an RSID is received
|
||||
without changing modem and frequency} xywh {15 276 155 20} down_box DOWN_BOX
|
||||
|
@ -2403,6 +2409,15 @@ progdefaults.changed = true;}
|
|||
changing frequency and modem} xywh {215 276 270 20} down_box DOWN_BOX
|
||||
code0 {chkRSidMark->value(progdefaults.rsid_mark);}
|
||||
}
|
||||
Fl_Check_Button chkRSidAutoDisable {
|
||||
label {Reception disables detector}
|
||||
callback {progdefaults.rsid_auto_disable = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Disable further detection when RSID is received} xywh {15 306 200 20} down_box DOWN_BOX
|
||||
code0 {if (progdefaults.rsid_notify_only) progdefaults.rsid_auto_disable = false;}
|
||||
code1 {chkRSidAutoDisable->value(progdefaults.rsid_auto_disable);}
|
||||
code2 {if (progdefaults.rsid_notify_only) chkRSidAutoDisable->deactivate();}
|
||||
}
|
||||
}
|
||||
}
|
||||
Fl_Group tabMisc {
|
||||
|
|
|
@ -1246,21 +1246,9 @@ void cbTune(Fl_Widget *w, void *) {
|
|||
restoreFocus();
|
||||
}
|
||||
|
||||
void cbRSID(Fl_Widget *w, void *) {
|
||||
if (trx_state == STATE_TX || trx_state == STATE_TUNE) {
|
||||
btnRSID->value(0);
|
||||
return;
|
||||
}
|
||||
if (progdefaults.rsid == true) {
|
||||
progdefaults.rsid = false;
|
||||
wf->xmtrcv->activate();
|
||||
btnTune->activate();
|
||||
} else {
|
||||
ReedSolomon->reset();
|
||||
progdefaults.rsid = true;
|
||||
wf->xmtrcv->deactivate();
|
||||
btnTune->deactivate();
|
||||
}
|
||||
void cbRSID(Fl_Widget *w, void *)
|
||||
{
|
||||
progdefaults.rsid = btnRSID->value();
|
||||
restoreFocus();
|
||||
}
|
||||
|
||||
|
@ -3410,7 +3398,6 @@ void setReverse(int rev) {
|
|||
|
||||
void start_tx()
|
||||
{
|
||||
if (progdefaults.rsid == true) return;
|
||||
trx_transmit();
|
||||
REQ(&waterfall::set_XmtRcvBtn, wf, true);
|
||||
}
|
||||
|
|
|
@ -291,6 +291,7 @@ extern Fl_Check_Button *chkTransmitRSid;
|
|||
extern Fl_Check_Button *chkRSidWideSearch;
|
||||
extern Fl_Check_Button *chkRSidNotifyOnly;
|
||||
extern Fl_Check_Button *chkRSidMark;
|
||||
extern Fl_Check_Button *chkRSidAutoDisable;
|
||||
extern Fl_Group *tabMisc;
|
||||
extern Fl_Tabs *tabsMisc;
|
||||
extern Fl_Group *tabSweetSpot;
|
||||
|
|
|
@ -52,6 +52,9 @@
|
|||
ELEM_(bool, rsid_notify_only, "RSIDNOTIFYONLY", \
|
||||
"Trigger RSID notifications but do not change modem and frequency", \
|
||||
false) \
|
||||
ELEM_(bool, rsid_auto_disable, "RSIDAUTODISABLE", \
|
||||
"Disable RSID detection when changing modem and/or frequency", \
|
||||
true) \
|
||||
\
|
||||
ELEM_(bool, slowcpu, "SLOWCPU", \
|
||||
"Disable expensive processing in some decoders", \
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
//
|
||||
// rsid.h
|
||||
//
|
||||
// Copyright (C) 2006
|
||||
// Copyright (C) 2008, 2009
|
||||
// Dave Freese, W1HKJ
|
||||
// Copyright (C) 2009
|
||||
// Stelios Bounanos, M0GLD
|
||||
//
|
||||
// This file is part of fldigi.
|
||||
//
|
||||
|
@ -40,11 +42,15 @@
|
|||
#ifndef RSID_H
|
||||
#define RSID_H
|
||||
|
||||
#include <samplerate.h>
|
||||
|
||||
#include "ringbuffer.h"
|
||||
#include "globals.h"
|
||||
#include "modem.h"
|
||||
|
||||
#define RSID_SAMPLE_RATE 11025.0
|
||||
|
||||
#define RSID_FFT_SAMPLES 512
|
||||
#define RSID_FFT_SIZE 1024
|
||||
#define RSID_ARRAY_SIZE (RSID_FFT_SIZE * 2)
|
||||
|
||||
|
@ -66,7 +72,6 @@ struct RSIDs { unsigned char rs; trx_mode mode; };
|
|||
|
||||
class cRsId {
|
||||
private:
|
||||
int _samplerate;
|
||||
// Table of precalculated Reed Solomon symbols
|
||||
unsigned char *pCodes;
|
||||
|
||||
|
@ -79,7 +84,7 @@ private:
|
|||
// Span of FFT bins, in which the RSID will be searched for
|
||||
int nBinLow;
|
||||
int nBinHigh;
|
||||
double aInputSamples[RSID_ARRAY_SIZE];
|
||||
float aInputSamples[RSID_ARRAY_SIZE];
|
||||
double fftwindow[RSID_ARRAY_SIZE];
|
||||
double aFFTReal[RSID_ARRAY_SIZE];
|
||||
double aFFTAmpl[RSID_FFT_SIZE];
|
||||
|
@ -98,6 +103,12 @@ private:
|
|||
int DistanceOut;
|
||||
int MetricsOut;
|
||||
|
||||
// resample
|
||||
SRC_STATE* src_state;
|
||||
SRC_DATA src_data;
|
||||
float* inptr;
|
||||
static long src_callback(void* cb_data, float** data);
|
||||
|
||||
// transmit
|
||||
double *outbuf;
|
||||
size_t symlen;
|
||||
|
@ -107,12 +118,13 @@ private:
|
|||
int HammingDistance(int iBucket, unsigned char *p2);
|
||||
void CalculateBuckets(const double *pSpectrum, int iBegin, int iEnd);
|
||||
bool search_amp( int &pSymbolOut, int &pBinOut);
|
||||
void search(void);
|
||||
void apply (int iSymbol, int iBin);
|
||||
public:
|
||||
cRsId();
|
||||
~cRsId();
|
||||
void reset();
|
||||
void search(const double *pSamples, size_t nSamples);
|
||||
void apply (int iSymbol, int iBin);
|
||||
void receive(const float* buf, size_t len);
|
||||
void send(bool postidle);
|
||||
};
|
||||
|
||||
|
|
|
@ -79,7 +79,8 @@ protected:
|
|||
SNDFILE* ofCapture;
|
||||
SNDFILE* ifPlayback;
|
||||
SNDFILE* ofGenerate;
|
||||
sf_count_t read_file(SNDFILE* file, double* buf, size_t count);
|
||||
sf_count_t read_file(SNDFILE* file, float* buf, size_t count);
|
||||
sf_count_t write_file(SNDFILE* file, float* buf, size_t count);
|
||||
sf_count_t write_file(SNDFILE* file, double* buf, size_t count);
|
||||
bool format_supported(int format);
|
||||
void tag_file(SNDFILE *sndfile, const char *title);
|
||||
|
@ -97,7 +98,7 @@ public:
|
|||
virtual void Abort(unsigned dir = UINT_MAX) = 0;
|
||||
virtual size_t Write(double *, size_t) = 0;
|
||||
virtual size_t Write_stereo(double *, double *, size_t) = 0;
|
||||
virtual size_t Read(double *, size_t) = 0;
|
||||
virtual size_t Read(float *, size_t) = 0;
|
||||
virtual void flush(unsigned dir = UINT_MAX) = 0;
|
||||
virtual bool must_close(void) = 0;
|
||||
#if USE_SNDFILE
|
||||
|
@ -148,7 +149,7 @@ public:
|
|||
void Abort(unsigned dir = UINT_MAX) { Close(dir); }
|
||||
size_t Write(double *, size_t);
|
||||
size_t Write_stereo(double *, double *, size_t);
|
||||
size_t Read(double *, size_t);
|
||||
size_t Read(float *, size_t);
|
||||
bool must_close(void) { return true; }
|
||||
void flush(unsigned dir = UINT_MAX) { wait_till_finished(); }
|
||||
|
||||
|
@ -191,7 +192,7 @@ public:
|
|||
void Abort(unsigned dir = UINT_MAX);
|
||||
size_t Write(double *buf, size_t count);
|
||||
size_t Write_stereo(double *bufleft, double *bufright, size_t count);
|
||||
size_t Read(double *buf, size_t count);
|
||||
size_t Read(float *buf, size_t count);
|
||||
bool must_close(void);
|
||||
void flush(unsigned dir = UINT_MAX);
|
||||
|
||||
|
@ -274,7 +275,7 @@ public:
|
|||
void Abort(unsigned dir = UINT_MAX);
|
||||
size_t Write(double* buf, size_t count);
|
||||
size_t Write_stereo(double* bufleft, double* bufright, size_t count);
|
||||
size_t Read(double *buf, size_t count);
|
||||
size_t Read(float *buf, size_t count);
|
||||
bool must_close(void) { return false; }
|
||||
void flush(unsigned dir = UINT_MAX);
|
||||
|
||||
|
@ -320,7 +321,7 @@ public:
|
|||
void Abort(unsigned) { }
|
||||
size_t Write(double* buf, size_t count);
|
||||
size_t Write_stereo(double* bufleft, double* bufright, size_t count);
|
||||
size_t Read(double *buf, size_t count);
|
||||
size_t Read(float *buf, size_t count);
|
||||
bool must_close(void) { return false; }
|
||||
void flush(unsigned) { }
|
||||
};
|
||||
|
|
|
@ -1116,7 +1116,7 @@ public:
|
|||
Main_toggle_lock()
|
||||
{
|
||||
_signature = "b:n";
|
||||
_help = "Toggles the Reverse Sideband state. Returns the new state.";
|
||||
_help = "Toggles the Transmit Lock state. Returns the new state.";
|
||||
}
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
{
|
||||
|
@ -1128,6 +1128,54 @@ public:
|
|||
|
||||
// =============================================================================
|
||||
|
||||
class Main_get_rsid : public xmlrpc_c::method
|
||||
{
|
||||
public:
|
||||
Main_get_rsid()
|
||||
{
|
||||
_signature = "b:n";
|
||||
_help = "Returns the RSID state.";
|
||||
}
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
{
|
||||
*retval = xmlrpc_c::value_boolean(btnRSID->value());
|
||||
}
|
||||
};
|
||||
|
||||
class Main_set_rsid : public xmlrpc_c::method
|
||||
{
|
||||
public:
|
||||
Main_set_rsid()
|
||||
{
|
||||
_signature = "b:b";
|
||||
_help = "Sets the RSID state. Returns the old state.";
|
||||
}
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
{
|
||||
bool v = btnRSID->value();
|
||||
REQ(set_button, btnRSID, params.getBoolean(0));
|
||||
*retval = xmlrpc_c::value_boolean(v);
|
||||
}
|
||||
};
|
||||
|
||||
class Main_toggle_rsid : public xmlrpc_c::method
|
||||
{
|
||||
public:
|
||||
Main_toggle_rsid()
|
||||
{
|
||||
_signature = "b:n";
|
||||
_help = "Toggles the RSID state. Returns the new state.";
|
||||
}
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
{
|
||||
bool v = !btnRSID->value();
|
||||
REQ(set_button, btnRSID, v);
|
||||
*retval = xmlrpc_c::value_boolean(v);
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class Main_get_trx_status : public xmlrpc_c::method
|
||||
{
|
||||
public:
|
||||
|
@ -1142,8 +1190,6 @@ public:
|
|||
*retval = xmlrpc_c::value_string("tune");
|
||||
else if (wf->xmtrcv->value())
|
||||
*retval = xmlrpc_c::value_string("tx");
|
||||
else if (btnRSID->value())
|
||||
*retval = xmlrpc_c::value_string("rsid");
|
||||
else
|
||||
*retval = xmlrpc_c::value_string("rx");
|
||||
}
|
||||
|
@ -1159,11 +1205,8 @@ public:
|
|||
}
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
{
|
||||
if (!wf->xmtrcv->value()) {
|
||||
if (btnRSID->value())
|
||||
REQ(set_button, btnRSID, false);
|
||||
if (!wf->xmtrcv->value())
|
||||
REQ(set_button, wf->xmtrcv, true);
|
||||
}
|
||||
*retval = xmlrpc_c::value_nil();
|
||||
}
|
||||
};
|
||||
|
@ -1178,11 +1221,8 @@ public:
|
|||
}
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
{
|
||||
if (!btnTune->value()) {
|
||||
if (btnRSID->value())
|
||||
REQ(set_button, btnRSID, false);
|
||||
if (!btnTune->value())
|
||||
REQ(set_button, btnTune, !btnTune->value());
|
||||
}
|
||||
*retval = xmlrpc_c::value_nil();
|
||||
}
|
||||
};
|
||||
|
@ -1199,8 +1239,6 @@ public:
|
|||
{
|
||||
if (wf->xmtrcv->value())
|
||||
REQ(set_button, wf->xmtrcv, false);
|
||||
else if (btnRSID->value())
|
||||
REQ(set_button, btnRSID, false);
|
||||
*retval = xmlrpc_c::value_nil();
|
||||
}
|
||||
};
|
||||
|
@ -1257,7 +1295,7 @@ public:
|
|||
Main_rsid()
|
||||
{
|
||||
_signature = "n:n";
|
||||
_help = "Waits for RSID.";
|
||||
_help = "Deprecated; use main.{get,set,toggle}_rsid instead.";
|
||||
}
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
{
|
||||
|
@ -1946,6 +1984,10 @@ public:
|
|||
ELEM_(Main_set_lock, "main.set_lock") \
|
||||
ELEM_(Main_toggle_lock, "main.toggle_lock") \
|
||||
\
|
||||
ELEM_(Main_get_rsid, "main.get_rsid") \
|
||||
ELEM_(Main_set_rsid, "main.set_rsid") \
|
||||
ELEM_(Main_toggle_rsid, "main.toggle_rsid") \
|
||||
\
|
||||
ELEM_(Main_get_trx_status, "main.get_trx_status") \
|
||||
ELEM_(Main_tx, "main.tx") \
|
||||
ELEM_(Main_tune, "main.tune") \
|
||||
|
|
|
@ -1,7 +1,35 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// rsid.cxx
|
||||
//
|
||||
// Copyright (C) 2008, 2009
|
||||
// Dave Freese, W1HKJ
|
||||
// Copyright (C) 2009
|
||||
// Stelios Bounanos, M0GLD
|
||||
//
|
||||
// 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 <cmath>
|
||||
#include <cstring>
|
||||
#include <float.h>
|
||||
#include <samplerate.h>
|
||||
|
||||
#include "rsid.h"
|
||||
#include "filters.h"
|
||||
|
@ -13,6 +41,7 @@
|
|||
#include "confdialog.h"
|
||||
#include "qrunner.h"
|
||||
#include "notify.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "rsid_fft.cxx"
|
||||
|
||||
|
@ -228,8 +257,16 @@ const int cRsId::indices[] = {
|
|||
2, 4, 8, 9, 11, 15, 7, 14, 5, 10, 13, 3
|
||||
};
|
||||
|
||||
cRsId :: cRsId()
|
||||
cRsId::cRsId()
|
||||
{
|
||||
int error;
|
||||
src_state = src_new(progdefaults.sample_converter, 1, &error);
|
||||
if (error) {
|
||||
LOG_ERROR("src_new error %d: %s", error, src_strerror(error));
|
||||
abort();
|
||||
}
|
||||
src_data.end_of_input = 0;
|
||||
|
||||
reset();
|
||||
|
||||
memset(aHashTable1, 255, sizeof(aHashTable1));
|
||||
|
@ -256,8 +293,6 @@ cRsId :: cRsId()
|
|||
nBinLow = RSID_RESOL + 1;
|
||||
nBinHigh = RSID_FFT_SIZE - 32;
|
||||
|
||||
_samplerate = 11025;
|
||||
|
||||
outbuf = 0;
|
||||
symlen = 0;
|
||||
}
|
||||
|
@ -266,6 +301,7 @@ cRsId::~cRsId()
|
|||
{
|
||||
delete [] pCodes;
|
||||
delete [] outbuf;
|
||||
src_delete(src_state);
|
||||
}
|
||||
|
||||
void cRsId::reset()
|
||||
|
@ -277,6 +313,12 @@ void cRsId::reset()
|
|||
memset(aFFTReal, 0, sizeof(aFFTReal));
|
||||
memset(aFFTAmpl, 0, sizeof(aFFTAmpl));
|
||||
memset(aBuckets, 0, sizeof(aBuckets));
|
||||
|
||||
int error = src_reset(src_state);
|
||||
if (error)
|
||||
LOG_ERROR("src_reset error %d: %s", error, src_strerror(error));
|
||||
src_data.src_ratio = 0.0;
|
||||
inptr = aInputSamples + RSID_FFT_SAMPLES;
|
||||
}
|
||||
|
||||
void cRsId::Encode(int code, unsigned char *rsid)
|
||||
|
@ -324,8 +366,50 @@ void cRsId::CalculateBuckets(const double *pSpectrum, int iBegin, int iEnd)
|
|||
}
|
||||
}
|
||||
|
||||
void cRsId::receive(const float* buf, size_t len)
|
||||
{
|
||||
double src_ratio = RSID_SAMPLE_RATE / active_modem->get_samplerate();
|
||||
bool resample = (fabs(src_ratio - 1.0) >= DBL_EPSILON);
|
||||
size_t ns;
|
||||
|
||||
void cRsId::search(const double *pSamples, size_t nSamples)
|
||||
while (len) {
|
||||
ns = inptr - aInputSamples;
|
||||
if (ns >= RSID_FFT_SAMPLES) // inptr points to second half of aInputSamples
|
||||
ns -= RSID_FFT_SAMPLES;
|
||||
ns = RSID_FFT_SAMPLES - ns; // number of additional samples we need to call search()
|
||||
|
||||
if (resample) {
|
||||
if (src_data.src_ratio != src_ratio)
|
||||
src_set_ratio(src_state, src_data.src_ratio = src_ratio);
|
||||
src_data.data_in = const_cast<float*>(buf);
|
||||
src_data.input_frames = len;
|
||||
src_data.data_out = inptr;
|
||||
src_data.output_frames = ns;
|
||||
src_data.input_frames_used = 0;
|
||||
int error = src_process(src_state, &src_data);
|
||||
if (unlikely(error)) {
|
||||
LOG_ERROR("src_process error %d: %s", error, src_strerror(error));
|
||||
return;
|
||||
}
|
||||
inptr += src_data.output_frames_gen;
|
||||
buf += src_data.input_frames_used;
|
||||
len -= src_data.input_frames_used;
|
||||
}
|
||||
else {
|
||||
ns = MIN(ns, len);
|
||||
memcpy(inptr, buf, ns * sizeof(*inptr));
|
||||
inptr += ns;
|
||||
buf += ns;
|
||||
len -= ns;
|
||||
}
|
||||
|
||||
ns = inptr - aInputSamples;
|
||||
if (ns == RSID_FFT_SAMPLES || ns == RSID_FFT_SIZE)
|
||||
search(); // will reset inptr if at end of input
|
||||
}
|
||||
}
|
||||
|
||||
void cRsId::search(void)
|
||||
{
|
||||
if (progdefaults.rsidWideSearch) {
|
||||
nBinLow = RSID_RESOL + 1;
|
||||
|
@ -343,14 +427,18 @@ void cRsId::search(const double *pSamples, size_t nSamples)
|
|||
nBinHigh = RSID_FFT_SIZE - nBinLow;
|
||||
}
|
||||
|
||||
size_t ns = nSamples;
|
||||
if (ns > RSID_ARRAY_SIZE / 4) {
|
||||
ns = RSID_ARRAY_SIZE / 4;
|
||||
}
|
||||
memmove(aInputSamples, aInputSamples + ns, ns * sizeof(double));
|
||||
memcpy(aInputSamples + ns, pSamples, ns * sizeof(double));
|
||||
for (int i = 0; i < RSID_FFT_SIZE; i++)
|
||||
aFFTReal[i] = aInputSamples[i] * fftwindow[i];
|
||||
if (inptr == aInputSamples + RSID_FFT_SIZE) {
|
||||
for (int i = 0; i < RSID_FFT_SIZE; i++)
|
||||
aFFTReal[i] = aInputSamples[i] * fftwindow[i];
|
||||
inptr = aInputSamples;
|
||||
}
|
||||
else { // second half of aInputSamples is older
|
||||
for (size_t i = RSID_FFT_SAMPLES; i < RSID_FFT_SIZE; i++)
|
||||
aFFTReal[i - RSID_FFT_SAMPLES] = aInputSamples[i] * fftwindow[i - RSID_FFT_SAMPLES];
|
||||
for (size_t i = 0; i < RSID_FFT_SAMPLES; i++)
|
||||
aFFTReal[i + RSID_FFT_SAMPLES] = aInputSamples[i] * fftwindow[i + RSID_FFT_SAMPLES];
|
||||
}
|
||||
|
||||
memset(aFFTReal + RSID_FFT_SIZE, 0, RSID_FFT_SIZE * sizeof(double));
|
||||
rsrfft(aFFTReal, 11);
|
||||
|
||||
|
@ -387,7 +475,7 @@ void cRsId::apply(int iSymbol, int iBin)
|
|||
mbin = rsid_ids[n].mode;
|
||||
break;
|
||||
}
|
||||
if (!progdefaults.rsid_notify_only)
|
||||
if (!progdefaults.rsid_notify_only && progdefaults.rsid_auto_disable)
|
||||
REQ(toggleRSID);
|
||||
|
||||
if (mbin == NUM_MODES) return;
|
||||
|
|
|
@ -81,7 +81,7 @@ SoundBase::SoundBase()
|
|||
: sample_frequency(0),
|
||||
txppm(progdefaults.TX_corr), rxppm(progdefaults.RX_corr),
|
||||
tx_src_state(0), rx_src_state(0),
|
||||
wrt_buffer(new double [SND_BUF_LEN]),
|
||||
wrt_buffer(new double[SND_BUF_LEN]),
|
||||
#if USE_SNDFILE
|
||||
ofCapture(0), ifPlayback(0), ofGenerate(0),
|
||||
#endif
|
||||
|
@ -129,7 +129,7 @@ void SoundBase::get_file_params(const char* def_fname, const char** fname, int*
|
|||
*format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
|
||||
break;
|
||||
case 1:
|
||||
*format = SF_FORMAT_AU | SF_FORMAT_DOUBLE | SF_ENDIAN_CPU;
|
||||
*format = SF_FORMAT_AU | SF_FORMAT_FLOAT | SF_ENDIAN_CPU;
|
||||
break;
|
||||
case 2:
|
||||
*format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16;
|
||||
|
@ -231,13 +231,13 @@ int SoundBase::Generate(bool val)
|
|||
return 1;
|
||||
}
|
||||
|
||||
sf_count_t SoundBase::read_file(SNDFILE* file, double* buf, size_t count)
|
||||
sf_count_t SoundBase::read_file(SNDFILE* file, float* buf, size_t count)
|
||||
{
|
||||
sf_count_t r = sf_readf_double(file, buf, count);
|
||||
sf_count_t r = sf_readf_float(file, buf, count);
|
||||
|
||||
while (r < (sf_count_t)count) {
|
||||
sf_seek(file, 0, SEEK_SET);
|
||||
r += sf_readf_double(file, buf + r, count - r);
|
||||
r += sf_readf_float(file, buf + r, count - r);
|
||||
if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
@ -245,17 +245,34 @@ sf_count_t SoundBase::read_file(SNDFILE* file, double* buf, size_t count)
|
|||
return r;
|
||||
}
|
||||
|
||||
#define WRITE_FILE(type_, file_, buf_, count_) \
|
||||
if (capture || !progdefaults.EnableMixer) \
|
||||
return sf_writef_ ## type_(file, buf, count); \
|
||||
/* generated audio; apply transmit mixer level */ \
|
||||
size_t nw = count; \
|
||||
type_* wrtbuf = (type_*)wrt_buffer; \
|
||||
for (size_t n = MIN(SND_BUF_LEN, count); count; count -= n) { \
|
||||
for (size_t i = 0; i < n; i++) \
|
||||
wrtbuf[i] = buf[i] * progStatus.XmtMixer; \
|
||||
if (sf_writef_ ## type_(file, wrtbuf, n) != n) { \
|
||||
LOG_ERROR("sf_write error: %s", sf_strerror(file)); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
return nw - count
|
||||
|
||||
|
||||
sf_count_t SoundBase::write_file(SNDFILE* file, float* buf, size_t count)
|
||||
{
|
||||
WRITE_FILE(float, file, buf, count);
|
||||
}
|
||||
|
||||
sf_count_t SoundBase::write_file(SNDFILE* file, double* buf, size_t count)
|
||||
{
|
||||
if (capture || !progdefaults.EnableMixer)
|
||||
return sf_writef_double(file, buf, count);
|
||||
else {
|
||||
for (size_t n = 0; n < count; n++)
|
||||
wrt_buffer[n] = buf[n] * progStatus.XmtMixer;
|
||||
return sf_write_double(file, wrt_buffer, count);
|
||||
}
|
||||
WRITE_FILE(double, file, buf, count);
|
||||
}
|
||||
|
||||
|
||||
bool SoundBase::format_supported(int format)
|
||||
{
|
||||
|
||||
|
@ -298,7 +315,7 @@ void SoundBase::tag_file(SNDFILE *sndfile, const char *title)
|
|||
|
||||
#if USE_OSS
|
||||
|
||||
#define MAXSC 32767.0
|
||||
#define MAXSC 32767.0f
|
||||
#define maxsc 32000.0
|
||||
|
||||
SoundOSS::SoundOSS(const char *dev ) {
|
||||
|
@ -505,7 +522,7 @@ bool SoundOSS::reset_device()
|
|||
return 1; /* sounddevice has been reset */
|
||||
}
|
||||
|
||||
size_t SoundOSS::Read(double *buffer, size_t buffersize)
|
||||
size_t SoundOSS::Read(float *buffer, size_t buffersize)
|
||||
{
|
||||
short int *ibuff = (short int *)cbuff;
|
||||
int numread;
|
||||
|
@ -952,7 +969,7 @@ void SoundPort::Abort(unsigned dir)
|
|||
} while (0)
|
||||
|
||||
|
||||
size_t SoundPort::Read(double *buf, size_t count)
|
||||
size_t SoundPort::Read(float *buf, size_t count)
|
||||
{
|
||||
#if USE_SNDFILE
|
||||
if (playback) {
|
||||
|
@ -1018,9 +1035,13 @@ size_t SoundPort::Read(double *buf, size_t count)
|
|||
sd[0].advance = 0;
|
||||
}
|
||||
|
||||
// convert to double
|
||||
for (size_t i = 0; i < count; i++)
|
||||
buf[i] = rbuf[sd[0].params.channelCount * i];
|
||||
if (sd[0].params.channelCount == 1)
|
||||
memcpy(buf, rbuf, count * sizeof(float));
|
||||
else {
|
||||
// write first channel
|
||||
for (size_t i = 0; i < count; i++)
|
||||
buf[i] = rbuf[sd[0].params.channelCount * i];
|
||||
}
|
||||
|
||||
#if USE_SNDFILE
|
||||
if (capture)
|
||||
|
@ -1719,7 +1740,7 @@ long SoundPulse::src_read_cb(void* arg, float** data)
|
|||
return p->sd[0].blocksize;
|
||||
}
|
||||
|
||||
size_t SoundPulse::Read(double *buf, size_t count)
|
||||
size_t SoundPulse::Read(float *buf, size_t count)
|
||||
{
|
||||
#if USE_SNDFILE
|
||||
if (playback) {
|
||||
|
@ -1744,20 +1765,17 @@ size_t SoundPulse::Read(double *buf, size_t count)
|
|||
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)) == 0)
|
||||
if ((r = src_callback_read(rx_src_state, sd[0].src_ratio, count - n, buf + n)) == 0)
|
||||
return n;
|
||||
n += r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int err;
|
||||
if (pa_simple_read(sd[0].stream, fbuf, sizeof(float) * count, &err) == -1)
|
||||
if (pa_simple_read(sd[0].stream, buf, sizeof(float) * count, &err) == -1)
|
||||
throw SndPulseException(err);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
buf[i] = fbuf[i];
|
||||
|
||||
#if USE_SNDFILE
|
||||
if (capture)
|
||||
write_file(ofCapture, buf, count);
|
||||
|
@ -1815,7 +1833,7 @@ size_t SoundNull::Write_stereo(double* bufleft, double* bufright, size_t count)
|
|||
return count;
|
||||
}
|
||||
|
||||
size_t SoundNull::Read(double *buf, size_t count)
|
||||
size_t SoundNull::Read(float *buf, size_t count)
|
||||
{
|
||||
#if USE_SNDFILE
|
||||
if (playback) {
|
||||
|
|
|
@ -73,21 +73,20 @@ static int _trx_tune;
|
|||
// Ringbuffer for the audio "history". A pointer into this buffer
|
||||
// is also passed to the waterfall signal drawing routines.
|
||||
#define NUMMEMBUFS 1024
|
||||
ringbuffer<double> trxrb(ceil2(NUMMEMBUFS * SCBLOCKSIZE));
|
||||
static ringbuffer<double> trxrb(ceil2(NUMMEMBUFS * SCBLOCKSIZE));
|
||||
// Vector used for direct access to the ringbuffer
|
||||
ringbuffer<double>::vector_type rbvec[2];
|
||||
static ringbuffer<double>::vector_type rbvec[2];
|
||||
static float fbuf[SCBLOCKSIZE];
|
||||
bool bHistory = false;
|
||||
|
||||
static bool trxrunning = false;
|
||||
|
||||
static bool rsid_detecting = false;
|
||||
|
||||
#include "tune.cxx"
|
||||
|
||||
//=============================================================================
|
||||
void trx_trx_receive_loop()
|
||||
{
|
||||
int numread;
|
||||
size_t numread;
|
||||
int current_samplerate;
|
||||
assert(powerof2(SCBLOCKSIZE));
|
||||
|
||||
|
@ -126,56 +125,16 @@ void trx_trx_receive_loop()
|
|||
active_modem->rx_init();
|
||||
|
||||
while (1) {
|
||||
if (progdefaults.rsid == true && rsid_detecting == false) {
|
||||
rsid_detecting = true;
|
||||
try {
|
||||
current_samplerate = RSID_SAMPLE_RATE;
|
||||
scard->Open(O_RDONLY, current_samplerate);
|
||||
}
|
||||
catch (const SndException& e) {
|
||||
LOG_ERROR("%s", e.what());
|
||||
put_status(e.what(), 5);
|
||||
scard->Close();
|
||||
if (e.error() == EBUSY && progdefaults.btnAudioIOis == SND_IDX_PORT) {
|
||||
sound_close();
|
||||
sound_init();
|
||||
}
|
||||
MilliSleep(1000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (progdefaults.rsid == false && rsid_detecting == true) {
|
||||
rsid_detecting = false;
|
||||
active_modem->rx_init();
|
||||
try {
|
||||
current_samplerate = active_modem->get_samplerate();
|
||||
scard->Open(O_RDONLY, current_samplerate);
|
||||
}
|
||||
catch (const SndException& e) {
|
||||
LOG_ERROR("%s", e.what());
|
||||
put_status(e.what(), 5);
|
||||
scard->Close();
|
||||
if (e.error() == EBUSY && progdefaults.btnAudioIOis == SND_IDX_PORT) {
|
||||
sound_close();
|
||||
sound_init();
|
||||
}
|
||||
MilliSleep(1000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If we change to an 8000Hz modem while RSID is on we'll never detect anything.
|
||||
// Toggle rsid_detecting so that the audio device is reopened with the ReedSolomon
|
||||
// samplerate in the next loop iteration.
|
||||
if (progdefaults.rsid && rsid_detecting && current_samplerate != RSID_SAMPLE_RATE)
|
||||
rsid_detecting = false;
|
||||
|
||||
try {
|
||||
numread = 0;
|
||||
while (numread < SCBLOCKSIZE && trx_state == STATE_RX)
|
||||
numread += scard->Read(fbuf + numread, SCBLOCKSIZE - numread);
|
||||
if (trxrb.write_space() == 0) // discard some old data
|
||||
trxrb.read_advance(SCBLOCKSIZE);
|
||||
trxrb.get_wv(rbvec);
|
||||
numread = 0;
|
||||
while (numread < SCBLOCKSIZE && trx_state == STATE_RX)
|
||||
numread += scard->Read(rbvec[0].buf + numread, SCBLOCKSIZE - numread);
|
||||
// convert to double and write to rb
|
||||
for (size_t i = 0; i < numread; i++)
|
||||
rbvec[0].buf[i] = fbuf[i];
|
||||
}
|
||||
catch (const SndException& e) {
|
||||
scard->Close();
|
||||
|
@ -191,10 +150,9 @@ void trx_trx_receive_loop()
|
|||
REQ(&waterfall::sig_data, wf, rbvec[0].buf, numread, current_samplerate);
|
||||
|
||||
if (!bHistory) {
|
||||
if (rsid_detecting == true)
|
||||
ReedSolomon->search(rbvec[0].buf, numread);
|
||||
else
|
||||
active_modem->rx_process(rbvec[0].buf, numread);
|
||||
active_modem->rx_process(rbvec[0].buf, numread);
|
||||
if (progdefaults.rsid)
|
||||
ReedSolomon->receive(fbuf, numread);
|
||||
}
|
||||
else {
|
||||
bool afc = progStatus.afconoff;
|
||||
|
@ -239,9 +197,9 @@ void trx_trx_transmit_loop()
|
|||
push2talk->set(true);
|
||||
active_modem->tx_init(scard);
|
||||
|
||||
if (progdefaults.TransmitRSid == true)
|
||||
if (progdefaults.TransmitRSid)
|
||||
ReedSolomon->send(true);
|
||||
|
||||
|
||||
while (trx_state == STATE_TX) {
|
||||
try {
|
||||
if (active_modem->tx_process() < 0)
|
||||
|
@ -256,10 +214,10 @@ void trx_trx_transmit_loop()
|
|||
}
|
||||
}
|
||||
|
||||
if (progdefaults.TransmitRSid == true)
|
||||
if (progdefaults.TransmitRSid)
|
||||
ReedSolomon->send(false);
|
||||
|
||||
scard->flush();
|
||||
|
||||
scard->flush();
|
||||
if (scard->must_close())
|
||||
scard->Close();
|
||||
} else
|
||||
|
|
Ładowanie…
Reference in New Issue