Browse Source

Prepare for new modes with multiple rates

Also use native rate for whole analog path.
master
Jeroen Vreeken 11 months ago
parent
commit
3f8d799051
14 changed files with 346 additions and 216 deletions
  1. +1
    -1
      ctcss.h
  2. +12
    -18
      dsp.c
  3. +1
    -1
      dtmf.h
  4. +1
    -0
      eth_ar_codec2.h
  5. +30
    -16
      freedv_eth.c
  6. +13
    -2
      freedv_eth.h
  7. +12
    -2
      freedv_eth_queue.c
  8. +18
    -15
      freedv_eth_rx.c
  9. +9
    -16
      freedv_eth_rxa.c
  10. +148
    -68
      freedv_eth_transcode.c
  11. +56
    -38
      freedv_eth_tx.c
  12. +8
    -39
      freedv_eth_txa.c
  13. +35
    -0
      sound.c
  14. +2
    -0
      sound.h

+ 1
- 1
ctcss.h View File

@ -33,7 +33,7 @@ int ctcss_add(struct ctcss *ctcss, int16_t *sound, int nr);
/* detection code in dsp.c */
int ctcss_detect_init(double freq);
int ctcss_detect_init(double freq, int rate);
bool ctcss_detect_rx(short *smp, int nr);
struct iir;


+ 12
- 18
dsp.c View File

@ -104,12 +104,6 @@ static double DTMF_RELATIVE_PEAK_ROW = 6.3; /* 8dB */
static double DTMF_RELATIVE_PEAK_COL = 6.3; /* 8dB */
static int SAMPLE_RATE = 8000;
typedef struct {
@ -193,10 +187,10 @@ static inline double goertzel_result(goertzel_state_t *s)
return (double)r.value * (double)(1 << r.power);
}
static inline void goertzel_init(goertzel_state_t *s, double freq, int samples)
static inline void goertzel_init(goertzel_state_t *s, double freq, int samples, int rate)
{
s->v2 = s->v3 = s->chunky = 0.0;
s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / SAMPLE_RATE));
s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / rate));
s->samples = samples;
}
@ -205,29 +199,29 @@ static inline void goertzel_reset(goertzel_state_t *s)
s->v2 = s->v3 = s->chunky = 0.0;
}
static void ast_dtmf_detect_init (dtmf_detect_state_t *s)
static void ast_dtmf_detect_init (dtmf_detect_state_t *s, int rate)
{
int i;
s->lasthit = 0;
s->current_hit = 0;
for (i = 0; i < 4; i++) {
goertzel_init (&s->row_out[i], dtmf_row[i], DTMF_OPTIMIZED_VALUE);
goertzel_init (&s->col_out[i], dtmf_col[i], DTMF_OPTIMIZED_VALUE);
goertzel_init (&s->row_out[i], dtmf_row[i], DTMF_OPTIMIZED_VALUE, rate);
goertzel_init (&s->col_out[i], dtmf_col[i], DTMF_OPTIMIZED_VALUE, rate);
s->energy = 0.0;
}
s->current_sample = 0;
}
static void ast_digit_detect_init(digit_detect_state_t *s)
static void ast_digit_detect_init(digit_detect_state_t *s, int rate)
{
/* s->current_digits = 0;
s->detected_digits = 0;
s->lost_digits = 0;
s->digits[0] = '\0';
*/
ast_dtmf_detect_init(&s->dtmf);
ast_dtmf_detect_init(&s->dtmf, rate);
}
/*
static void store_digit(digit_detect_state_t *s, char digit)
@ -387,10 +381,10 @@ int dtmf_rx(short *smp, int nr, void (*cb)(char *), bool *detected)
return 0;
}
int dtmf_init(void)
int dtmf_init(int rate)
{
ast_digit_detect_init(&dtmf);
ast_digit_detect_init(&dtmf, rate);
return 0;
}
@ -433,11 +427,11 @@ bool ctcss_detect_rx(short *smp, int nr)
return (ctcss_result & ctcss_threshold_mask) == ctcss_threshold_mask;
}
int ctcss_detect_init(double freq)
int ctcss_detect_init(double freq, int rate)
{
ctcss_samples = (SAMPLE_RATE * 8)/freq;
ctcss_samples = (rate * 8)/freq;
printf("RX CTCSS: %fHz, %d samples in bin (%dms)\n", freq, ctcss_samples, ctcss_samples/8);
goertzel_init(&ctcss_gs, freq, ctcss_samples);
goertzel_init(&ctcss_gs, freq, ctcss_samples, rate);
goertzel_reset(&ctcss_gs);
ctcss_samples_cur = 0;
ctcss_result = 0;


+ 1
- 1
dtmf.h View File

@ -5,6 +5,6 @@
int dtmf_rx(short *smp, int nr, void (*cb)(char *), bool *detected);
int dtmf_init(void);
int dtmf_init(int rate);
#endif /* _INCLUDE_DTMF_H_ */

+ 1
- 0
eth_ar_codec2.h View File

@ -98,6 +98,7 @@ static inline bool eth_ar_eth_p_iscodec2(uint16_t type)
case ETH_P_CODEC2_700:
case ETH_P_CODEC2_700B:
case ETH_P_CODEC2_700C:
case ETH_P_LPCNET_1733:
return true;
default:
break;


+ 30
- 16
freedv_eth.c View File

@ -55,7 +55,6 @@ static int freedv_rx_channel;
static int tx_codecmode;
static int analog_rx_channel;
static bool use_short;
static bool baseband_out;
static bool baseband_in;
static bool baseband_in_tx;
@ -68,6 +67,9 @@ static int tx_fprs_msec = 30000;
static bool freedv_hasdata;
static uint8_t mac[6];
static struct freedv_eth_transcode *tc = NULL;
static struct freedv_eth_transcode *tc_iface = NULL;
static struct nmea_state *nmea;
enum tx_mode {
@ -102,7 +104,7 @@ void freedv_eth_voice_rx(uint8_t to[6], uint8_t from[6], uint16_t eth_type, uint
memcpy(packet->data, data, len);
memcpy(packet->from, from, 6);
freedv_eth_transcode(packet, tx_codecmode, eth_type);
freedv_eth_transcode(tc, packet, tx_codecmode, eth_type);
packet->local_rx = local_rx;
enqueue_voice(packet, 0, -10);
@ -115,20 +117,23 @@ void freedv_eth_voice_rx(uint8_t to[6], uint8_t from[6], uint16_t eth_type, uint
memcpy(packet->data, data, len);
memcpy(packet->from, from, 6);
freedv_eth_transcode(packet, CODEC_MODE_NATIVE16, eth_type);
freedv_eth_transcode(tc, packet, CODEC_MODE_NATIVE16, eth_type);
packet->local_rx = local_rx;
enqueue_baseband(packet);
}
}
if (eth_type == ETH_P_NATIVE16 && !use_short) {
size_t nr = len/2;
uint8_t alaw[nr];
int16_t *s16data = (void*)data;
alaw_encode(alaw, s16data, nr);
interface_rx(to, from, ETH_P_ALAW, alaw, nr, 0, 1);
if (eth_type == ETH_P_NATIVE16) {
packet = tx_packet_alloc();
packet->len = len;
memcpy(packet->data, data, len);
memcpy(packet->from, from, 6);
freedv_eth_transcode(tc_iface, packet, CODEC_MODE_ALAW, eth_type);
interface_rx(to, from, ETH_P_ALAW, packet->data, packet->len, 0, 1);
tx_packet_free(packet);
} else {
interface_rx(to, from, eth_type, data, len, 0, 1);
}
@ -179,7 +184,7 @@ static int cb_int_tx(uint8_t to[6], uint8_t from[6], uint16_t eth_type, uint8_t
memcpy(packet->data, data, len);
memcpy(packet->from, from, 6);
freedv_eth_transcode(packet, tx_codecmode, eth_type);
freedv_eth_transcode(tc, packet, tx_codecmode, eth_type);
int q = enqueue_voice(packet, transmission, eth_ar_dbm_decode(level));
@ -189,7 +194,7 @@ static int cb_int_tx(uint8_t to[6], uint8_t from[6], uint16_t eth_type, uint8_t
memcpy(packet->data, data, len);
memcpy(packet->from, from, 6);
freedv_eth_transcode(packet, CODEC_MODE_NATIVE16, eth_type);
freedv_eth_transcode(tc, packet, CODEC_MODE_NATIVE16, eth_type);
enqueue_baseband(packet);
}
@ -326,7 +331,7 @@ int main(int argc, char **argv)
fullduplex = atoi(freedv_eth_config_value("fullduplex", NULL, "0"));
repeater = atoi(freedv_eth_config_value("repeater", NULL, "0"));
verbose = atoi(freedv_eth_config_value("verbose", NULL, "0"));
char *freedv_mode_str = freedv_eth_config_value("freedv_mode", NULL, "700");
char *freedv_mode_str = freedv_eth_config_value("freedv_mode", NULL, "1600");
rig_model = atoi(freedv_eth_config_value("rig_model", NULL, "1"));
char *rig_file = freedv_eth_config_value("rig_file", NULL, NULL);
char *ptt_file = freedv_eth_config_value("rig_ptt_file", NULL, NULL);
@ -349,7 +354,6 @@ int main(int argc, char **argv)
int dcd_threshold = atoi(freedv_eth_config_value("analog_rx_dcd_threshold", NULL, "1"));
bool tx_tone = atoi(freedv_eth_config_value("analog_tx_tone", NULL, "0"));
int dtmf_mute = atoi(freedv_eth_config_value("analog_dtmf_mute", NULL, "1"));
use_short = atoi(freedv_eth_config_value("analog_rx_short", NULL, "0"));
baseband_out = atoi(freedv_eth_config_value("baseband_out", NULL, "0"));
baseband_in = atoi(freedv_eth_config_value("baseband_in", NULL, "0"));
baseband_in_tx = atoi(freedv_eth_config_value("baseband_in_tx", NULL, "0"));
@ -381,9 +385,16 @@ int main(int argc, char **argv)
} else if (!strcmp(freedv_mode_str, "800XA")) {
freedv_mode = FREEDV_MODE_800XA;
freedv_hasdata = true;
#if defined(FREEDV_MODE_2020)
} else if (!strcmp(freedv_mode_str, "2020")) {
freedv_mode = FREEDV_MODE_2020;
freedv_hasdata = false;
#endif
#if defined(FREEDV_MODE_6000)
} else if (!strcmp(freedv_mode_str, "6000")) {
freedv_mode = FREEDV_MODE_6000;
freedv_hasdata = true;
#endif
} else {
printf("Invalid FreeDV mode\n");
return -1;
@ -505,6 +516,9 @@ int main(int argc, char **argv)
if (sound_rate < 0)
return -1;
tc = freedv_eth_transcode_init(sound_rate);
tc_iface = freedv_eth_transcode_init(sound_rate);
if (tx_mode == TX_MODE_FREEDV) {
int freedv_rate = freedv_get_modem_sample_rate(freedv);
printf("freedv sample rate: %d\n", freedv_rate);
@ -575,13 +589,13 @@ int main(int argc, char **argv)
poll(fds, nfds, -1);
if (sound_poll_out_tx(fds, sound_fdc_tx)) {
if (tx_mode == TX_MODE_MIXED) {
bool q_v = queue_voice_filled();
bool q_v = queue_voice_filled(1);
bool q_d = queue_data_filled() || queue_control_filled();
bool tx_v = freedv_eth_txa_ptt();
bool tx_d = freedv_eth_tx_ptt();
if (tx_d || (!tx_v && !q_v && q_d)) {
freedv_eth_txa_state_machine();
freedv_eth_tx_state_machine();
} else {
freedv_eth_txa_state_machine();
}


+ 13
- 2
freedv_eth.h View File

@ -49,13 +49,20 @@ static inline uint16_t freedv_eth_mode2type(int mode)
case FREEDV_MODE_2400B:
type = ETH_P_CODEC2_1300;
break;
#if defined(FREEDV_MODE_2020)
case FREEDV_MODE_2020:
type = ETH_P_LPCNET_1733;
break;
#endif
case FREEDV_MODE_700C:
case FREEDV_MODE_700D:
type = ETH_P_CODEC2_700C;
break;
#if defined(FREEDV_MODE_6000)
case FREEDV_MODE_6000:
type = ETH_P_CODEC2_3200;
break;
#endif
default:
break;
}
@ -86,7 +93,7 @@ void tx_packet_free(struct tx_packet *packet);
struct tx_packet *dequeue_voice(void);
struct tx_packet *peek_voice(void);
int enqueue_voice(struct tx_packet *packet, uint8_t transmission, double level_dbm);
bool queue_voice_filled(void);
bool queue_voice_filled(size_t min_len);
void queue_voice_end(uint8_t transmission);
struct tx_packet *dequeue_baseband(void);
@ -108,7 +115,11 @@ bool queue_control_filled(void);
void freedv_eth_voice_rx(uint8_t to[6], uint8_t from[6], uint16_t eth_type, uint8_t *data, size_t len, bool local_rx, uint8_t transmission, double level);
bool freedv_eth_cdc(void);
int freedv_eth_transcode(struct tx_packet *packet, int to_codecmode, uint16_t from_type);
struct freedv_eth_transcode;
struct freedv_eth_transcode * freedv_eth_transcode_init(int native_rate);
int freedv_eth_transcode(struct freedv_eth_transcode *tc, struct tx_packet *packet, int to_codecmode, uint16_t from_type);
int freedv_eth_tx_init(struct freedv *init_freedv, uint8_t init_mac[6],
struct nmea_state *init_nmea, bool init_fullduplex,


+ 12
- 2
freedv_eth_queue.c View File

@ -93,9 +93,19 @@ int enqueue_voice(struct tx_packet *packet, uint8_t transmission, double level_d
return 1;
}
bool queue_voice_filled(void)
bool queue_voice_filled(size_t min_len)
{
return queue_voice;
size_t len = 0;
struct tx_packet *entry;
for (entry = queue_voice; entry; entry = entry->next) {
len += entry->len;
if (len >= min_len) {
return true;
}
}
return false;
}
void queue_voice_end(uint8_t transmission)


+ 18
- 15
freedv_eth_rx.c View File

@ -32,8 +32,8 @@ static bool cdc;
static int16_t *samples_rx = NULL;
static int bytes_per_codec_frame;
static int bytes_per_eth_frame;
static int bytes_per_freedv_frame;
static int bytes_per_codec2_frame;
static uint16_t eth_type_rx;
static void *silence_packet = NULL;
static struct sound_resample *sr = NULL;
@ -81,7 +81,7 @@ void freedv_eth_rx(int16_t *hw_samples, int hw_nr)
nr_rx += copy;
if (nr_rx == nin) {
unsigned char packed_codec_bits[bytes_per_codec_frame];
unsigned char packed_codec_bits[bytes_per_freedv_frame];
bool old_cdc = cdc;
@ -104,11 +104,11 @@ void freedv_eth_rx(int16_t *hw_samples, int hw_nr)
cdc |= (ret && rx_sync > RX_SYNC_THRESHOLD);
if (ret && cdc) {
int i;
for (i = 0; i < bytes_per_codec_frame/bytes_per_eth_frame; i++) {
for (i = 0; i < bytes_per_freedv_frame/bytes_per_codec2_frame; i++) {
freedv_eth_voice_rx(
bcast, rx_add, eth_type_rx,
packed_codec_bits + i * bytes_per_eth_frame,
bytes_per_eth_frame, true,
packed_codec_bits + i * bytes_per_codec2_frame,
bytes_per_codec2_frame, true,
transmission, level_dbm);
}
printf(".");
@ -120,11 +120,11 @@ void freedv_eth_rx(int16_t *hw_samples, int hw_nr)
printf("*");
fflush(NULL);
if (cdc_voice) {
for (i = 0; i < bytes_per_codec_frame/bytes_per_eth_frame; i++) {
for (i = 0; i < bytes_per_freedv_frame/bytes_per_codec2_frame; i++) {
freedv_eth_voice_rx(
bcast, rx_add, eth_type_rx,
silence_packet,
bytes_per_eth_frame, true,
bytes_per_codec2_frame, true,
transmission, level_dbm);
}
}
@ -193,16 +193,16 @@ static void create_silence_packet(struct CODEC2 *c2)
int16_t samples[nr];
free(silence_packet);
silence_packet = calloc(1, bytes_per_eth_frame);
silence_packet = calloc(1, bytes_per_codec2_frame);
memset(samples, 0, nr * sizeof(int16_t));
int i;
unsigned char *sp = silence_packet;
for (i = 0; i < bytes_per_codec_frame/bytes_per_eth_frame; i++) {
for (i = 0; i < bytes_per_freedv_frame/bytes_per_codec2_frame; i++) {
codec2_encode(c2, sp, samples);
sp += bytes_per_codec_frame;
sp += bytes_per_freedv_frame;
}
}
@ -222,11 +222,14 @@ int freedv_eth_rx_init(struct freedv *init_freedv, uint8_t init_mac[6], int hw_r
sr = NULL;
}
bytes_per_eth_frame = codec2_bits_per_frame(freedv_get_codec2(freedv));
bytes_per_eth_frame += 7;
bytes_per_eth_frame /= 8;
bytes_per_codec2_frame = codec2_bits_per_frame(freedv_get_codec2(freedv));
bytes_per_codec2_frame += 7;
bytes_per_codec2_frame /= 8;
printf("RX bytes per codec2 frame: %d\n", bytes_per_codec2_frame);
int rat = freedv_get_n_codec_bits(freedv) / codec2_bits_per_frame(freedv_get_codec2(freedv));
bytes_per_codec_frame = bytes_per_eth_frame * rat;
printf("RX codec2 frames per freedv frame: %d\n", rat);
bytes_per_freedv_frame = bytes_per_codec2_frame * rat;
printf("RX bytes per freedv frame: %d\n", bytes_per_freedv_frame);
nr_samples = freedv_get_n_max_modem_samples(freedv);
create_silence_packet(freedv_get_codec2(freedv));


+ 9
- 16
freedv_eth_rxa.c View File

@ -37,8 +37,8 @@ static bool dtmf_initialized = false;
static bool cdc;
static bool ctcss_sql;
static int dtmf_mute = 1;
static struct sound_resample *sr = NULL;
static float rx_gain = 1.0;
static float limit = 1.0;
static char dtmf_control_start = '*';
static char dtmf_control_stop = '#';
@ -82,8 +82,6 @@ static void cb_control(char *ctrl)
void freedv_eth_rxa(int16_t *samples, int nr)
{
int nr_a = sound_resample_nr_out(sr, nr);
int16_t mod_a[nr_a];
bool detected;
bool new_cdc = false;
bool skip_prep = false;
@ -96,12 +94,12 @@ void freedv_eth_rxa(int16_t *samples, int nr)
if (st && !skip_prep)
speex_preprocess_run(st, samples);
sound_resample_perform_gain_limit(sr, mod_a, samples, nr_a, nr, rx_gain);
sound_gain_limit(samples, nr, rx_gain, &limit);
if (emphasis_d)
emphasis_de(emphasis_d, mod_a, nr_a);
emphasis_de(emphasis_d, samples, nr);
if (ctcss_sql) {
new_cdc = ctcss_detect_rx(mod_a, nr_a);
new_cdc = ctcss_detect_rx(samples, nr);
}
if (cdc && !new_cdc) {
queue_voice_end(transmission);
@ -109,16 +107,16 @@ void freedv_eth_rxa(int16_t *samples, int nr)
}
cdc = new_cdc;
dtmf_rx(mod_a, nr_a, cb_control, &detected);
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(mod_a, 0, nr_a * sizeof(int16_t));
memset(samples, 0, nr * sizeof(int16_t));
}
if (cdc) {
freedv_eth_voice_rx(bcast, mac, ETH_P_NATIVE16, (uint8_t *)mod_a, nr_a * sizeof(int16_t), true, transmission, level_dbm);
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;
}
@ -128,19 +126,14 @@ int freedv_eth_rxa_init(int hw_rate, uint8_t mac_init[6],
bool emphasis, double ctcss_freq, int dtmf_mute_init,
float rx_gain_init, int hw_nr)
{
int a_rate = FREEDV_ALAW_RATE;
rx_gain = rx_gain_init;
memcpy(mac, mac_init, 6);
printf("Analog rx gain: %f\n", rx_gain);
cdc = false;
sound_resample_destroy(sr);
sr = sound_resample_create(a_rate, hw_rate);
if (!dtmf_initialized) {
dtmf_init();
dtmf_init(hw_rate);
dtmf_initialized = true;
}
dtmf_mute = dtmf_mute_init;
@ -151,7 +144,7 @@ int freedv_eth_rxa_init(int hw_rate, uint8_t mac_init[6],
emphasis_d = emphasis_init();
if (ctcss_freq > 0.0) {
ctcss_detect_init(ctcss_freq);
ctcss_detect_init(ctcss_freq, hw_rate);
ctcss_sql = true;
} else {
ctcss_sql = false;


+ 148
- 68
freedv_eth_transcode.c View File

@ -20,25 +20,73 @@
#include "eth_ar_codec2.h"
#include "eth_ar/alaw.h"
#include "eth_ar/ulaw.h"
#include "stdio.h"
#include <stdio.h>
#include "sound.h"
#include <stdlib.h>
#include <string.h>
static struct CODEC2 *trans_enc;
static struct CODEC2 *trans_dec;
static short *trans_speech;
static int trans_speech_size;
static int trans_speech_pos;
static int trans_dec_mode = -1;
static int trans_enc_mode = -1;
static int trans_enc_samples_frame;
static int trans_enc_bytes_frame;
int freedv_eth_transcode(struct tx_packet *packet, int to_codecmode, uint16_t from_type)
struct freedv_eth_transcode {
struct CODEC2 *trans_enc;
struct CODEC2 *trans_dec;
short *trans_speech;
int trans_speech_size;
int trans_speech_pos;
int trans_dec_mode;
int trans_enc_mode;
int trans_enc_samples_frame;
int trans_enc_bytes_frame;
int trans_rate_native;
struct sound_resample *sr;
int sr_rate_in;
int sr_rate_out;
};
struct freedv_eth_transcode *freedv_eth_transcode_init(int native_rate)
{
printf("Transcode native audio rate: %d\n", native_rate);
struct freedv_eth_transcode *tc = calloc(1, sizeof(struct freedv_eth_transcode));
tc->trans_dec_mode = -1;
tc->trans_enc_mode = -1;
tc->trans_rate_native = native_rate;
return tc;
}
static inline int eth_ar_codec_rate(struct freedv_eth_transcode *tc, int mode)
{
switch(mode) {
case CODEC_MODE_LE16:
case CODEC_MODE_BE16:
return tc->trans_rate_native;
case CODEC_MODE_LPCNET_1733:
return 16000;
case CODEC_MODE_ALAW:
case CODEC_MODE_ULAW:
case CODEC2_MODE_3200:
case CODEC2_MODE_2400:
case CODEC2_MODE_1600:
case CODEC2_MODE_1400:
case CODEC2_MODE_1300:
case CODEC2_MODE_1200:
case CODEC2_MODE_700C:
case CODEC2_MODE_450:
case CODEC2_MODE_450PWB:
default:
return 8000;
}
}
int freedv_eth_transcode(struct freedv_eth_transcode *tc, struct tx_packet *packet, int to_codecmode, uint16_t from_type)
{
int from_codecmode = eth_ar_eth_p_codecmode(from_type);
int samples;
int samples_in;
int from_rate = eth_ar_codec_rate(tc, from_codecmode);
int to_rate = eth_ar_codec_rate(tc, to_codecmode);
if (to_codecmode == from_codecmode)
return 0;
@ -46,39 +94,32 @@ int freedv_eth_transcode(struct tx_packet *packet, int to_codecmode, uint16_t fr
switch(from_codecmode) {
case CODEC_MODE_ALAW:
case CODEC_MODE_ULAW:
samples = packet->len;
samples_in = packet->len;
break;
case CODEC_MODE_LE16:
case CODEC_MODE_BE16:
samples = packet->len / 2;
samples_in = packet->len / 2;
break;
default: {
if (from_codecmode != trans_dec_mode) {
if (trans_dec)
codec2_destroy(trans_dec);
trans_dec_mode = from_codecmode;
trans_dec = codec2_create(trans_dec_mode);
if (from_codecmode != tc->trans_dec_mode) {
if (tc->trans_dec)
codec2_destroy(tc->trans_dec);
tc->trans_dec_mode = from_codecmode;
tc->trans_dec = codec2_create(tc->trans_dec_mode);
}
samples = codec2_samples_per_frame(trans_dec);
samples_in = codec2_samples_per_frame(tc->trans_dec);
break;
}
}
if (trans_speech_pos + samples > trans_speech_size) {
short *tmp = realloc(trans_speech, sizeof(short)*(trans_speech_pos + samples));
if (!tmp)
return -1;
trans_speech = tmp;
trans_speech_size = trans_speech_pos + samples;
}
short *speech = trans_speech + trans_speech_pos;
short *speech_in = malloc(sizeof(short)*(samples_in));
switch (from_codecmode) {
case CODEC_MODE_ALAW:
alaw_decode(speech, packet->data, samples);
alaw_decode(speech_in, packet->data, samples_in);
break;
case CODEC_MODE_ULAW:
ulaw_decode(speech, packet->data, samples);
ulaw_decode(speech_in, packet->data, samples_in);
break;
case CODEC_MODE_LE16: {
/* Fill packet with native short samples */
@ -87,10 +128,10 @@ int freedv_eth_transcode(struct tx_packet *packet, int to_codecmode, uint16_t fr
uint16_t s;
} b2s;
int i;
for (i = 0; i < samples; i++) {
for (i = 0; i < samples_in; i++) {
b2s.b[0] = packet->data[i * 2 + 0];
b2s.b[1] = packet->data[i * 2 + 1];
speech[i] = le16toh(b2s.s);
speech_in[i] = le16toh(b2s.s);
}
}
case CODEC_MODE_BE16: {
@ -100,70 +141,109 @@ int freedv_eth_transcode(struct tx_packet *packet, int to_codecmode, uint16_t fr
uint16_t s;
} b2s;
int i;
for (i = 0; i < samples; i++) {
for (i = 0; i < samples_in; i++) {
b2s.b[0] = packet->data[i * 2 + 0];
b2s.b[1] = packet->data[i * 2 + 1];
speech[i] = be16toh(b2s.s);
speech_in[i] = be16toh(b2s.s);
}
}
default:
codec2_decode(trans_dec, speech, packet->data);
codec2_decode(tc->trans_dec, speech_in, packet->data);
break;
}
trans_speech_pos += samples;
int samples_out = 0;
if (to_rate == from_rate) {
samples_out = samples_in;
if (tc->sr) {
sound_resample_destroy(tc->sr);
tc->sr = NULL;
}
} else {
if (tc->sr_rate_in != from_rate || tc->sr_rate_out != to_rate) {
if (tc->sr) {
sound_resample_destroy(tc->sr);
tc->sr = NULL;
}
}
if (!tc->sr) {
printf("Transcode with resample: %d -> %d\n", from_rate, to_rate);
tc->sr_rate_in = from_rate;
tc->sr_rate_out = to_rate;
tc->sr = sound_resample_create(tc->sr_rate_out, tc->sr_rate_in);
}
if (tc->sr) {
samples_out = sound_resample_nr_out(tc->sr, samples_in);
}
}
if (tc->trans_speech_pos + samples_out > tc->trans_speech_size) {
short *tmp = realloc(tc->trans_speech, sizeof(short)*(tc->trans_speech_pos + samples_out));
if (!tmp)
return -1;
tc->trans_speech = tmp;
tc->trans_speech_size = tc->trans_speech_pos + samples_out;
}
short *speech_out = tc->trans_speech + tc->trans_speech_pos;
if (!tc->sr) {
memcpy(speech_out, speech_in, samples_out);
} else {
sound_resample_perform(tc->sr, speech_out, speech_in, samples_out, samples_in);
}
tc->trans_speech_pos += samples_out;
switch(to_codecmode) {
case CODEC_MODE_ALAW: {
if (trans_speech_pos > tx_packet_max())
trans_speech_pos = tx_packet_max();
alaw_encode(packet->data, trans_speech, trans_speech_pos);
packet->len = trans_speech_pos;
trans_speech_pos = 0;
if (tc->trans_speech_pos > tx_packet_max())
tc->trans_speech_pos = tx_packet_max();
alaw_encode(packet->data, tc->trans_speech, tc->trans_speech_pos);
packet->len = tc->trans_speech_pos;
tc->trans_speech_pos = 0;
break;
}
case CODEC_MODE_ULAW: {
if (trans_speech_pos > tx_packet_max())
trans_speech_pos = tx_packet_max();
ulaw_encode(packet->data, trans_speech, trans_speech_pos);
packet->len = trans_speech_pos;
trans_speech_pos = 0;
if (tc->trans_speech_pos > tx_packet_max())
tc->trans_speech_pos = tx_packet_max();
ulaw_encode(packet->data, tc->trans_speech, tc->trans_speech_pos);
packet->len = tc->trans_speech_pos;
tc->trans_speech_pos = 0;
break;
}
case CODEC_MODE_NATIVE16: {
/* Fill packet with native short samples */
if (trans_speech_pos > tx_packet_max())
trans_speech_pos = tx_packet_max();
memcpy(packet->data, trans_speech, trans_speech_pos * sizeof(short));
packet->len = trans_speech_pos * sizeof(short);
trans_speech_pos = 0;
if (tc->trans_speech_pos > tx_packet_max())
tc->trans_speech_pos = tx_packet_max();
memcpy(packet->data, tc->trans_speech, tc->trans_speech_pos * sizeof(short));
packet->len = tc->trans_speech_pos * sizeof(short);
tc->trans_speech_pos = 0;
break;
}
default:
if (to_codecmode != trans_enc_mode) {
if (trans_enc)
codec2_destroy(trans_enc);
trans_enc_mode = to_codecmode;
trans_enc = codec2_create(trans_enc_mode);
trans_enc_samples_frame = codec2_samples_per_frame(trans_enc);
trans_enc_bytes_frame = codec2_bits_per_frame(trans_enc);
trans_enc_bytes_frame += 7;
trans_enc_bytes_frame /= 8;
if (to_codecmode != tc->trans_enc_mode) {
if (tc->trans_enc)
codec2_destroy(tc->trans_enc);
tc->trans_enc_mode = to_codecmode;
tc->trans_enc = codec2_create(tc->trans_enc_mode);
tc->trans_enc_samples_frame = codec2_samples_per_frame(tc->trans_enc);
tc->trans_enc_bytes_frame = codec2_bits_per_frame(tc->trans_enc);
tc->trans_enc_bytes_frame += 7;
tc->trans_enc_bytes_frame /= 8;
}
packet->len = 0;
int off = 0;
while (trans_speech_pos - off >= trans_enc_samples_frame) {
codec2_encode(trans_enc, packet->data + packet->len, trans_speech + off);
off += trans_enc_samples_frame;
packet->len += trans_enc_bytes_frame;
while (tc->trans_speech_pos - off >= tc->trans_enc_samples_frame) {
codec2_encode(tc->trans_enc, packet->data + packet->len, tc->trans_speech + off);
off += tc->trans_enc_samples_frame;
packet->len += tc->trans_enc_bytes_frame;
}
if (off && off != trans_speech_pos) {
memmove(trans_speech, trans_speech + off, sizeof(short)*(trans_speech_pos - off));
if (off && off != tc->trans_speech_pos) {
memmove(tc->trans_speech, tc->trans_speech + off, sizeof(short)*(tc->trans_speech_pos - off));
}
trans_speech_pos -= off;
tc->trans_speech_pos -= off;
break;
}


+ 56
- 38
freedv_eth_tx.c View File

@ -39,8 +39,8 @@ static int tx_state_fprs_cnt;
static uint8_t bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static uint8_t mac[6];
static uint8_t tx_add[6];
static int bytes_per_codec_frame;
static int bytes_per_eth_frame;
static int bytes_per_freedv_frame;
static int bytes_per_codec2_frame;
static bool vc_busy = false;
static bool fullduplex;
static int tx_delay;
@ -120,7 +120,7 @@ static void data_tx(void)
tx_sound_out(mod_out, nom_modem_samples);
if (tx_state == TX_STATE_ON) {
if (queue_voice_filled())
if (queue_voice_filled(bytes_per_freedv_frame))
printf("x");
else
printf("+");
@ -135,36 +135,53 @@ static void tx_voice(void)
check_tx_add();
struct tx_packet *packet = dequeue_voice();
uint8_t *data = packet->data;
size_t len = packet->len;
size_t len = 0;
unsigned char frame_data[bytes_per_freedv_frame];
size_t frame_len = 0;
while (len) {
if (len < bytes_per_codec_frame) {
len = 0;
while (len < bytes_per_freedv_frame) {
size_t copy = bytes_per_freedv_frame - frame_len;
struct tx_packet *packet = peek_voice();
if (packet->len < copy)
copy = packet->len;
memcpy(frame_data + frame_len, packet->data, copy);
frame_len += copy;
if (packet->len > copy) {
memmove(packet->data, packet->data + copy, packet->len - copy);
} else {
double energy = codec2_get_energy(freedv_get_codec2(freedv), data);
bool fprs_late = nmea && tx_state_fprs_cnt >= tx_fprs && nmea->position_valid;
bool header_late = tx_state_data_header_cnt >= tx_header;
bool have_data = fprs_late || queue_data_filled() || header_late;
dequeue_voice();
tx_packet_free(packet);
}
}
bool fprs_late = nmea && tx_state_fprs_cnt >= tx_fprs && nmea->position_valid;
bool header_late = tx_state_data_header_cnt >= tx_header;
bool have_data = fprs_late || queue_data_filled() || header_late;
bool send_data_frame = tx_state_data_header_cnt >= tx_header_max;
struct CODEC2 *codec2 = freedv_get_codec2(freedv);
if (codec2) {
double energy = codec2_get_energy(codec2, data);
send_data_frame |= have_data && energy < 15.0;
send_data_frame |= !vc_busy && energy < 1.0;
}
// printf("e: %f %d %d\n", energy, vc_busy, tx_state_data_header_cnt);
// printf("e: %f %d %d\n", energy, vc_busy, tx_state_data_header_cnt);
if (tx_state_data_header_cnt >= tx_header_max ||
(have_data && energy < 15.0) ||
(!vc_busy && energy < 1.0)) {
data_tx();
} else {
freedv_codectx(freedv, mod_out, data);
if (send_data_frame) {
data_tx();
} else {
freedv_codectx(freedv, mod_out, data);
tx_sound_out(mod_out, nom_modem_samples);
tx_sound_out(mod_out, nom_modem_samples);
printf("-");
fflush(NULL);
}
len -= bytes_per_codec_frame;
}
printf("-");
fflush(NULL);
}
tx_packet_free(packet);
}
@ -202,7 +219,7 @@ void freedv_eth_tx_state_machine(void)
tx_state_cnt++;
switch (tx_state) {
case TX_STATE_OFF:
if ((queue_voice_filled() || queue_data_filled()) && (!freedv_eth_cdc() || fullduplex)) {
if ((queue_voice_filled(bytes_per_freedv_frame) || queue_data_filled()) && (!freedv_eth_cdc() || fullduplex)) {
// printf("OFF -> DELAY\n");
tx_state = TX_STATE_DELAY;
tx_state_cnt = 0;
@ -223,14 +240,14 @@ void freedv_eth_tx_state_machine(void)
tx_state_data_header_cnt = 0;
tx_state_fprs_cnt = tx_fprs - tx_header - 1;
}
if (queue_voice_filled()) {
if (queue_voice_filled(bytes_per_freedv_frame)) {
tx_voice();
} else {
data_tx();
}
break;
case TX_STATE_ON:
if (!queue_voice_filled() &&
if (!queue_voice_filled(bytes_per_freedv_frame) &&
!queue_data_filled() && freedv_data_ntxframes(freedv) <= 1 &&
!vc_busy) {
// printf("ON -> TAIL\n");
@ -239,7 +256,7 @@ void freedv_eth_tx_state_machine(void)
}
tx_state_data_header_cnt++;
tx_state_fprs_cnt++;
if (queue_voice_filled()) {
if (queue_voice_filled(bytes_per_freedv_frame)) {
tx_voice();
} else {
data_tx();
@ -253,14 +270,14 @@ void freedv_eth_tx_state_machine(void)
set_ptt = true;
ptt = IO_HL_PTT_OFF;
} else {
if (queue_voice_filled() || queue_data_filled()) {
if (queue_voice_filled(bytes_per_freedv_frame) || queue_data_filled()) {
// printf("TAIL -> ON\n");
tx_state = TX_STATE_ON;
tx_state_cnt = 0;
check_tx_add();
}
if (queue_voice_filled()) {
if (queue_voice_filled(bytes_per_freedv_frame)) {
tx_voice();
} else {
data_tx();
@ -344,13 +361,14 @@ int freedv_eth_tx_init(struct freedv *init_freedv, uint8_t init_mac[6],
tx_state = TX_STATE_OFF;
io_hl_ptt_set(IO_HL_PTT_OFF);
bytes_per_eth_frame = codec2_bits_per_frame(freedv_get_codec2(freedv));
bytes_per_eth_frame += 7;
bytes_per_eth_frame /= 8;
printf("TX bytes per ethernet frame: %d\n", bytes_per_eth_frame);
bytes_per_codec2_frame = codec2_bits_per_frame(freedv_get_codec2(freedv));
bytes_per_codec2_frame += 7;
bytes_per_codec2_frame /= 8;
printf("TX bytes per codec2 frame: %d\n", bytes_per_codec2_frame);
int rat = freedv_get_n_codec_bits(freedv) / codec2_bits_per_frame(freedv_get_codec2(freedv));
printf("TX ethernet frames per freedv frame: %d\n", rat);
bytes_per_codec_frame = bytes_per_eth_frame * rat;
printf("TX codec2 frames per freedv frame: %d\n", rat);
bytes_per_freedv_frame = bytes_per_codec2_frame * rat;
printf("TX bytes per freedv frame: %d\n", bytes_per_freedv_frame);
int freedv_rate = freedv_get_modem_sample_rate(freedv);
printf("TX freedv rate: %d\n", freedv_rate);


+ 8
- 39
freedv_eth_txa.c View File

@ -43,7 +43,6 @@ static bool tx_hadvoice;
static bool tx_waslocal;
static int tx_tail;
static int tx_state_cnt;
static struct sound_resample *sr_l, *sr_r = NULL;
static struct ctcss *ctcss = NULL;
static struct beacon *beacon = NULL;
static struct emphasis *emphasis_p = NULL;
@ -65,26 +64,7 @@ static int tx_sound_out(int16_t *samples0, int16_t *samples1, int nr)
samples1 = (int16_t*)packet->data;
}
if (!sr_l) {
sound_out_lr(samples0, samples1, nr);
} else {
int nr_out = sound_resample_nr_out(sr_l, nr);
int16_t hw_mod_out_l[nr_out];
int16_t hw_mod_out_r[nr_out];
int16_t *out_l, *out_r;
if (samples0) {
sound_resample_perform(sr_l, hw_mod_out_l, samples0, nr_out, nr);
out_l = hw_mod_out_l;
} else
out_l = NULL;
if (samples1) {
sound_resample_perform(sr_r, hw_mod_out_r, samples1, nr_out, nr);
out_r = hw_mod_out_r;
} else
out_r = NULL;
sound_out_lr(out_l, out_r, nr_out);
}
sound_out_lr(samples0, samples1, nr);
if (packet) {
tx_packet_free(packet);
@ -336,11 +316,9 @@ int freedv_eth_txa_init(bool init_fullduplex, int hw_rate,
bool emphasis,
bool init_output_tone)
{
int a_rate = FREEDV_ALAW_RATE;
beep_1k = beacon_beep_create(a_rate, 1000.0, 0.45, 0.25, 0.25);
beep_1k2 = beacon_beep_create(a_rate, 1200.0, 0.15, 0.15, 0.25);
beep_2k = beacon_beep_create(a_rate, 2000.0, 0.10, 0.20, 0.25);
beep_1k = beacon_beep_create(hw_rate, 1000.0, 0.45, 0.25, 0.25);
beep_1k2 = beacon_beep_create(hw_rate, 1200.0, 0.15, 0.15, 0.25);
beep_2k = beacon_beep_create(hw_rate, 2000.0, 0.10, 0.20, 0.25);
fullduplex = init_fullduplex;
output_tone = init_output_tone;
@ -351,32 +329,23 @@ int freedv_eth_txa_init(bool init_fullduplex, int hw_rate,
tx_state_cnt = 0;
tx_hadvoice = false;
int period_msec = 1000 / (FREEDV_ALAW_RATE / nr_samples);
int period_msec = 1000 / (FREEDV_ALAW_RATE / FREEDV_ALAW_NR_SAMPLES);
printf("TX period: %d msec\n", period_msec);
tx_tail = tx_tail_msec / period_msec;
printf("TX tail: %d periods\n", tx_tail);
nr_samples = FREEDV_ALAW_NR_SAMPLES * hw_rate / FREEDV_ALAW_RATE;
sound_resample_destroy(sr_l);
sound_resample_destroy(sr_r);
if (a_rate != hw_rate) {
sr_l = sound_resample_create(hw_rate, a_rate);
sr_r = sound_resample_create(hw_rate, a_rate);
} else {
sr_l = NULL;
sr_r = NULL;
}
ctcss_destroy(ctcss);
ctcss = NULL;
if (ctcss_f != 0.0) {
ctcss = ctcss_init(a_rate, ctcss_f, ctcss_amp);
ctcss = ctcss_init(hw_rate, ctcss_f, ctcss_amp);
}
beacon_destroy(beacon);
beacon = NULL;
if (beacon_interval) {
beacon = beacon_init(a_rate, nr_samples, beacon_interval, beacon_msg);
beacon = beacon_init(hw_rate, nr_samples, beacon_interval, beacon_msg);
}
emphasis_destroy(emphasis_p);


+ 35
- 0
sound.c View File

@ -91,6 +91,41 @@ int sound_resample_perform(struct sound_resample *sr, int16_t *out, int16_t *in,
#define GAIN_LP_LENGTH 16000
int sound_gain_limit(int16_t *samples, int nr, float gain, float *limit)
{
float limitgain = *limit;
bool newlimit = false;
int i;
float topval = 0.0;
for (i = 0; i < nr; i++) {
topval = fmaxf(topval, fabsf(samples[i]));
}
topval /= 32768;
float max = 1.0 / (gain * limitgain);
if (topval > max) {
limitgain = 1.0 / (topval * gain);
newlimit = true;
}
float realgain = gain * limitgain;
for (i = 0; i < nr; i++) {
float fl_out = samples[i];
fl_out *= realgain;
if (fl_out > 32767)
fl_out = 32767;
if (fl_out < -32768)
fl_out = -32768;
samples[i] = fl_out;
if (!newlimit)
limitgain = ((limitgain * (GAIN_LP_LENGTH - 1)) + 1.0) / GAIN_LP_LENGTH;
}
*limit = limitgain;
return 0;
}
int sound_resample_perform_gain_limit(struct sound_resample *sr, int16_t *out, int16_t *in, int nr_out, int nr_in, float gain)
{
float fl_in[nr_in], fl_out[nr_out];


+ 2
- 0
sound.h View File

@ -47,4 +47,6 @@ int sound_resample_perform_gain_limit(struct sound_resample *sr, int16_t *out, i
int sound_resample_nr_out(struct sound_resample *sr, int nr_in);
int sound_resample_nr_in(struct sound_resample *sr, int nr_out);
int sound_gain_limit(int16_t *samples, int nr, float gain, float *limit);
#endif /* _INCLUDE_SOUND_H_ */

Loading…
Cancel
Save