Quisk version 4.2.29

This commit is contained in:
James C. Ahlstrom
2024-01-11 12:31:13 -05:00
parent 15375aa4ea
commit 26773d5d09
20 changed files with 361 additions and 316 deletions
+94 -29
View File
@@ -5,6 +5,7 @@
#include <complex.h> // Use native C99 complex type for fftw3
#include <fftw3.h>
#include <sys/types.h>
#include <stdbool.h>
#ifdef MS_WINDOWS
#include <winsock2.h>
@@ -107,7 +108,7 @@ static PyObject * pyApp; // Application instance
static int fft_size; // size of fft, e.g. 1024
int data_width; // number of points to return as graph data; fft_size * n
static int graph_width; // width of the graph in pixels
rx_mode_type rxMode; // 0 to 13: CWL, CWU, LSB, USB, AM, FM, EXT, DGT-U, DGT-L, DGT-IQ, IMD, FDV-U, FDV-L, DGT-FM
rx_mode_type rxMode; // 0 to 13: CWL, CWU, LSB, USB, AM, FM, EXT, DGT_U, DGT_L, DGT_IQ, IMD, FDV_U, FDV_L, DGT_FM
int quisk_noise_blanker; // noise blanker level, 0 for off
int quiskTxHoldState; // hold Tx until the repeater frequency shift is complete
int quisk_is_vna; // zero for normal program, one for the VNA program
@@ -150,6 +151,7 @@ static int waterfall_scroll_mode = 1; // draw the first lines multiple times
static int quisk_use_sidetone; // is there a sidetone volume control?
static int hl2_txbuf_errors; // errors in the Hermes-Lite2 Tx buffer
static int hl2_txbuf_state; // state machine for errors in the Hermes-Lite2 Tx buffer
static int freedv_monitor; // pass the Freedv audio to the speakers instead of to the demodulator
static complex double PySampleBuf[SAMP_BUFFER_SIZE]; // buffer for samples returned from Python
static int PySampleCount; // count of samples in buffer
@@ -1843,6 +1845,7 @@ static int quisk_process_decimate(complex double * cSamples, int nSamples, int b
static int quisk_process_demodulate(complex double * cSamples, double * dsamples, int nSamples, int bank, int nFilter, rx_mode_type rx_mode)
{ // Changes here will require changes to get_filter_rate();
int i;
bool isLSB;
complex double cx;
double d, di, dd;
static struct AgcState Agc1 = {0.3, 16000, 0}, Agc2 = {0.3, 16000, 0};
@@ -2138,40 +2141,100 @@ static int quisk_process_demodulate(complex double * cSamples, double * dsamples
}
break;
case FDV_U: // digital voice
case FDV_L: // Extra modes added by Dave Roberts, G8KBB, June 2020.
case FDV_L: // Extra modes added by Dave Roberts, G8KBB, June 2020. Modified by N2ADR 2024.
quisk_check_freedv_mode();
// added conditional for 2400A/B mmodes
// current coding assumes modem sample rate is 8000 16000 or 48000
if( n_modem_sample_rate <= 16000 )
// current coding assumes input rate n_modem_sample_rate is 8000 or 48000.
// decimate:
switch (n_modem_sample_rate) {
case 8000:
quisk_filter_srate = quisk_decim_srate / 6;
nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to16, 3);
if (bank == 0)
process_agc(&Agc1, cSamples, nSamples, 1);
else
process_agc(&Agc2, cSamples, nSamples, 1);
nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim16to8, 2);
break;
case 48000:
quisk_filter_srate = quisk_decim_srate;
break;
default:
quisk_filter_srate = quisk_decim_srate / 6;
QuiskPrintf("Bad FreeDV modem rate in quisk_process_demodulate\n");
break;
}
// filter and demodulate to mono audio:
isLSB = (rx_mode == FDV_L);
complex double cBuf[nSamples];
for (i = 0; i < nSamples; i++) {
cx = cRxFilterOut(cSamples[i], bank, nFilter);
if (isLSB)
dd = creal(cx) + cimag(cx);
else
dd = creal(cx) - cimag(cx);
if(bank == 0) {
measure_audio_sum += dd * dd;
measure_audio_count += 1;
}
cBuf[i] = dd;
}
// Perhaps decimate by an additional fraction
if (quisk_decim_srate != 48000) {
dd = quisk_decim_srate / 48000.0;
nSamples = cFracDecim(cSamples, nSamples, dd);
nSamples = cFracDecim(cBuf, nSamples, dd);
quisk_decim_srate = 48000;
}
quisk_filter_srate = n_speech_sample_rate;
// added conditional for 2400A/B mmodes
if( n_modem_sample_rate == 8000 )
nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim16to8, 2);
if (bank == 0)
process_agc(&Agc1, cBuf, nSamples, 0);
else
process_agc(&Agc2, cBuf, nSamples, 0);
// pass data decimated down to n_modem_sample_rate
// return data is as n_speech_sample_rate
if (pt_quisk_freedv_rx)
nSamples = (* pt_quisk_freedv_rx)(cSamples, dsamples, nSamples, bank);
if(bank == 0) {
for (i = 0; i < nSamples; i++) {
measure_audio_sum += dsamples[i] * dsamples[i];
measure_audio_count += 1;
}
// return data is at n_speech_sample_rate
#if 0
static double dmax_in = 0;
for (i = 0; i < nSamples; i++) {
dd = fabs(creal(cBuf[i])) / CLIP16;
if (dd > dmax_in)
dmax_in = dd;
}
// current coding assumes speech sample rate is only 8000 or 16000 - needs tweak for others
nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio24p3, 3);
if( n_speech_sample_rate == 8000 )
if (bank == 0 && measure_audio_count >= quisk_filter_srate * measure_audio_time) {
//printf("Max sample in %.0lf\n", dmax_in);
dmax_in = 0;
}
#endif
if (nSamples > n_max_modem_samples) {
printf ("FreeDV: nSamples %d exceeds max_modem_samples %d\n", nSamples, n_max_modem_samples);
nSamples = n_max_modem_samples;
}
short sBuf[nSamples];
for (i = 0; i < nSamples; i++)
sBuf[i] = (short)(creal(cBuf[i]) / CLIP16);
if (freedv_monitor) {
for (i = 0; i < nSamples; i++)
dsamples[i] = (float)sBuf[i] * CLIP16;
}
else {
if (pt_quisk_freedv_rx)
nSamples = (* pt_quisk_freedv_rx)(sBuf, dsamples, nSamples, bank);
}
#if 0
static double dmax_out = 0;
for (i = 0; i < nSamples; i++) {
dd = fabs(dsamples[i]) / CLIP16;
if (dd > dmax_out)
dmax_out = dd;
}
if (bank == 0 && measure_audio_count >= quisk_filter_srate * measure_audio_time) {
//printf(" Max sample out %.0lf\n", dmax_out);
dmax_out = 0;
}
#endif
// current coding assumes output rate n_speech_sample_rate is 8000 or 16000
switch (n_speech_sample_rate) {
case 8000:
nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio24p3, 3);
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand7);
break;
case 16000:
nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio24p3, 3);
break;
}
break;
}
if (bank == 0 && measure_audio_count >= quisk_filter_srate * measure_audio_time) {
@@ -2877,7 +2940,7 @@ static PyObject * get_filter_rate(PyObject * self, PyObject * args)
break;
case FDV_U: // digital voice
case FDV_L:
filter_srate = n_speech_sample_rate;
filter_srate = n_modem_sample_rate;
break;
}
//QuiskPrintf("Filter rate %d\n", filter_srate);
@@ -3113,13 +3176,15 @@ static PyObject * read_fftw_wisdom(PyObject * self, PyObject * args)
static PyObject * set_params(PyObject * self, PyObject * args, PyObject * keywds)
{ /* Call with keyword arguments ONLY; change local parameters */
static char * kwlist[] = {"quisk_is_vna", "rx_bytes", "rx_endian", "read_error", "clip",
"bscope_bytes", "bscope_endian", "bscope_size", "bandscopeScale", "hermes_pause", NULL} ;
"bscope_bytes", "bscope_endian", "bscope_size", "bandscopeScale", "hermes_pause",
"freedv_monitor", NULL} ;
int i, nbytes, read_error, clip, bscope_size, hermes_pause;
nbytes = read_error = clip = bscope_size = hermes_pause = -1;
if (!PyArg_ParseTupleAndKeywords (args, keywds, "|iiiiiiiidi", kwlist,
if (!PyArg_ParseTupleAndKeywords (args, keywds, "|iiiiiiiidii", kwlist,
&quisk_is_vna, &nbytes, &py_sample_rx_endian, &read_error, &clip,
&py_bscope_bytes, &py_bscope_endian, &bscope_size, &bandscopeScale, &hermes_pause))
&py_bscope_bytes, &py_bscope_endian, &bscope_size, &bandscopeScale, &hermes_pause,
&freedv_monitor))
return NULL;
if (nbytes != -1) {
py_sample_rx_bytes = nbytes;