You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

242 lines
6.4 KiB

/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2017
This program 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 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "freedv_eth.h"
#include "freedv_eth_config.h"
#include "io.h"
#include "dtmf.h"
#include "emphasis.h"
#include "interface.h"
#include "eth_ar/alaw.h"
#include "sound.h"
#include "ctcss.h"
#include "eth_ar_codec2.h"
#include <string.h>
#include <speex/speex_preprocess.h>
static struct emphasis *emphasis_d = NULL;
static uint8_t mac[ETH_AR_MAC_SIZE];
static uint8_t bcast[ETH_AR_MAC_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static bool dtmf_initialized = false;
static bool cdc;
static bool ctcss_sql;
static int dtmf_mute = 1;
static float rx_gain = 1.0;
static float limit = 1.0;
static char dtmf_control_start = '*';
static char dtmf_control_stop = '#';
static int rxa_dcd_threshold = 0;
static int rxa_dcd_cnt = 0;
static uint8_t transmission = 0;
static double level_dbm = -60;
enum dtmf_state {
DTMF_IDLE,
DTMF_CONTROL,
DTMF_CONTROL_TAIL,
};
static enum dtmf_state dtmf_state = DTMF_IDLE;
SpeexPreprocessState *st = NULL;
bool freedv_eth_rxa_cdc(void)
{
return cdc;
}
static void cb_control(char *ctrl)
{
uint8_t *msg = (uint8_t *)ctrl;
if (ctrl[0] == dtmf_control_start) {
dtmf_state = DTMF_CONTROL;
} else if (ctrl[0] == dtmf_control_stop) {
dtmf_state = DTMF_CONTROL_TAIL;
} else {
if (dtmf_state == DTMF_CONTROL_TAIL)
dtmf_state = DTMF_IDLE;
}
printf("DTMF: %s\n", ctrl);
interface_rx(bcast, mac, ETH_P_AR_CONTROL, msg, strlen(ctrl), 0, 1);
}
void freedv_eth_rxa(int16_t *samples, int nr)
{
bool detected;
bool new_cdc = false;
bool skip_prep = false;
if (!ctcss_sql) {
new_cdc = io_hl_dcd_get();
skip_prep = !new_cdc;
}
if (st && !skip_prep)
speex_preprocess_run(st, samples);
sound_gain_limit(samples, nr, rx_gain, &limit);
if (emphasis_d)
emphasis_de(emphasis_d, samples, nr);
if (ctcss_sql) {
new_cdc = ctcss_detect_rx(samples, nr);
}
if (cdc && !new_cdc) {
queue_voice_end(transmission);
transmission++;
}
if (!new_cdc) {
rxa_dcd_cnt = -rxa_dcd_threshold;
cdc = false;
} else {
if (rxa_dcd_cnt >= 0) {
cdc = true;
}
rxa_dcd_cnt += nr;
}
cdc = new_cdc;
dtmf_rx(samples, nr, cb_control, &detected);
if (detected) {
if ((dtmf_mute == 1) ||
(dtmf_mute == 2 && dtmf_state == DTMF_CONTROL) ||
(dtmf_mute == 2 && dtmf_state == DTMF_CONTROL_TAIL))
memset(samples, 0, nr * sizeof(int16_t));
}
if (cdc) {
freedv_eth_voice_rx(bcast, mac, ETH_P_NATIVE16, (uint8_t *)samples, nr * sizeof(int16_t), true, transmission, level_dbm);
} else {
dtmf_state = DTMF_IDLE;
}
}
int freedv_eth_rxa_init(int hw_rate, uint8_t mac_init[ETH_AR_MAC_SIZE],
bool emphasis, double ctcss_freq, int dtmf_mute_init,
float rx_gain_init, int hw_nr)
{
rx_gain = rx_gain_init;
memcpy(mac, mac_init, 6);
printf("Analog rx gain: %f\n", rx_gain);
int msec_samples = FREEDV_ALAW_RATE / 1000;
printf("RXA samples per msec: %d\n", msec_samples);
int rxa_delay_msec = atoi(freedv_eth_config_value("rx_delay", NULL, "0"));
rxa_dcd_threshold = rxa_delay_msec * msec_samples;
printf("RXA rx delay samples: %d\n", rxa_dcd_threshold);
rxa_dcd_cnt = -rxa_dcd_threshold;
cdc = false;
if (!dtmf_initialized) {
dtmf_init(hw_rate);
dtmf_initialized = true;
}
dtmf_mute = dtmf_mute_init;
emphasis_destroy(emphasis_d);
emphasis_d = NULL;
if (emphasis)
emphasis_d = emphasis_init();
if (ctcss_freq > 0.0) {
ctcss_detect_init(ctcss_freq, hw_rate);
ctcss_sql = true;
} else {
ctcss_sql = false;
}
bool denoise = atoi(freedv_eth_config_value("analog_rx_denoise", NULL, "1"));
if (denoise) {
printf("Analog denoise and AGC active\n");
spx_int32_t val;
float fval;
st = speex_preprocess_state_init(hw_nr, hw_rate);
val= denoise;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &val);
val = -15; //default -15
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &val);
val=1;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &val);
// Add factor 2.0 since speex seems to aim on half the value
fval=32768.0 / rx_gain;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &fval);
val = 40; // default 12
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_INCREMENT, &val);
val = -40; // default -40
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_DECREMENT, &val);
val=60; // default 30
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &val);
val= -15; // default -15
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE, &val);
/* preprocess info */
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_DENOISE, &val);
printf("DENOISE enabled: %d\n", val);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_AGC, &val);
printf("AGC enabled: %d\n", val);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_VAD, &val);
printf("VAD enabled: %d\n", val);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_DEREVERB, &val);
printf("DEREVERB enabled: %d\n", val);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_NOISE_SUPPRESS, &val);
printf("NOISE_SUPPRESS: %d\n", val);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS, &val);
printf("ECHO_SUPPRESS: %d\n", val);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE, &val);
printf("ECHO_SUPPRESS_ACTIVE: %d\n", val);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_AGC_LEVEL, &fval);
printf("AGC_LEVEL: %f\n", fval);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &val);
printf("AGC_INCREMENT: %d\n", val);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &val);
printf("AGC_DECREMENT:: %d\n", val);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &val);
printf("AGC_MAX_GAIN: %d\n", val);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_AGC_LEVEL, &fval);
printf("AGC_LEVEL:: %f\n", fval);
} else {
printf("No analog denoise and AGC\n");
}
return 0;
}