From 9a53b6685937c6b044a1003bec413d914587edad Mon Sep 17 00:00:00 2001 From: drowe67 Date: Sun, 2 Aug 2015 22:41:06 +0000 Subject: [PATCH] freedv api much improved by Jim Ahlstrom, thanks Jim git-svn-id: https://svn.code.sf.net/p/freetel/code@2248 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/src/freedv_api.c | 109 ++++++++++++++++++++++++++++++++++++ codec2-dev/src/freedv_api.h | 103 ++++++++++------------------------ codec2-dev/src/freedv_rx.c | 31 ++++++---- codec2-dev/src/freedv_tx.c | 19 ++++--- 4 files changed, 173 insertions(+), 89 deletions(-) diff --git a/codec2-dev/src/freedv_api.c b/codec2-dev/src/freedv_api.c index 4850247e..b6bc2d28 100644 --- a/codec2-dev/src/freedv_api.c +++ b/codec2-dev/src/freedv_api.c @@ -43,8 +43,18 @@ #include "golay23.h" #include "varicode.h" #include "freedv_api.h" +#include "freedv_api_internal.h" #include "comp_prim.h" +#define VERSION 10 /* The API version number. The first version is 10. Increment if the API changes + in a way that would require changes by the API user. */ +/* + * Version 10 Initial version August 2, 2015. + * Version 11 September + * Changes go here. + * + */ + #define NORM_PWR 1.74 /* experimentally derived fudge factor so 1600 and 700 mode have the same tx power */ @@ -771,3 +781,102 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { return nout; } +/*---------------------------------------------------------------------------*\ + + FUNCTION....: freedv_get_version + AUTHOR......: Jim Ahlstrom + DATE CREATED: 28 July 2015 + + Return the version of the FreeDV API. This is meant to help API users determine when + incompatible changes have occurred. + +\*---------------------------------------------------------------------------*/ + +int freedv_get_version(void) +{ + return VERSION; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: freedv_set_callback_txt + AUTHOR......: Jim Ahlstrom + DATE CREATED: 28 July 2015 + + Set the callback functions and the callback state pointer that will be used + for the aux txt channel. The freedv_callback_rx is a function pointer that + will be called to return received characters. The freedv_callback_tx is a + function pointer that will be called to send transmitted characters. The callback + state is a user-defined void pointer that will be passed to the callback functions. + Any or all can be NULL, and the default is all NULL. + The function signatures are: + void receive_char(void *callback_state, char c); + char transmit_char(void *callback_state); + +\*---------------------------------------------------------------------------*/ + +void freedv_set_callback_txt(struct freedv *f, freedv_callback_rx rx, freedv_callback_tx tx, void *state) +{ + f->freedv_put_next_rx_char = rx; + f->freedv_get_next_tx_char = tx; + f->callback_state = state; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: freedv_get_modem_stats + AUTHOR......: Jim Ahlstrom + DATE CREATED: 28 July 2015 + + Return data from the modem. The arguments are pointers to the data items. The + pointers can be NULL if the data item is not wanted. + +\*---------------------------------------------------------------------------*/ + +void freedv_get_modem_stats(struct freedv *f, int *sync, float *snr_est) +{ + if (f->mode == FREEDV_MODE_1600) + fdmdv_get_demod_stats(f->fdmdv, &f->stats); + if (f->mode == FREEDV_MODE_700) + cohpsk_get_demod_stats(f->cohpsk, &f->stats); + if (sync) *sync = f->stats.sync; + if (snr_est) *snr_est = f->stats.snr_est; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTIONS...: freedv_set_* + AUTHOR......: Jim Ahlstrom + DATE CREATED: 28 July 2015 + + Set some parameters used by FreeDV. It is possible to write a macro using ## for + this, but I wasn't sure it would be 100% portable. + +\*---------------------------------------------------------------------------*/ + +// Set integers +void freedv_set_test_frames (struct freedv *f, int val) {f->smooth_symbols = val;} +void freedv_set_squelch_en (struct freedv *f, int val) {f->squelch_en = val;} +// Set floats +void freedv_set_snr_squelch_thresh (struct freedv *f, float val) {f->snr_squelch_thresh = val;} + +/*---------------------------------------------------------------------------*\ + + FUNCTIONS...: freedv_get_* + AUTHOR......: Jim Ahlstrom + DATE CREATED: 28 July 2015 + + Get some parameters from FreeDV. It is possible to write a macro using ## for + this, but I wasn't sure it would be 100% portable. + +\*---------------------------------------------------------------------------*/ + +// Get integers +int freedv_get_test_frames (struct freedv *f) {return f->test_frames;} +int freedv_get_n_speech_samples (struct freedv *f) {return f->n_speech_samples;} +int freedv_get_n_max_modem_samples (struct freedv *f) {return f->n_max_modem_samples;} +int freedv_get_n_nom_modem_samples (struct freedv *f) {return f->n_nom_modem_samples;} +int freedv_get_total_bits (struct freedv *f) {return f->total_bits;} +int freedv_get_total_bit_errors (struct freedv *f) {return f->total_bit_errors;} +// Get floats + diff --git a/codec2-dev/src/freedv_api.h b/codec2-dev/src/freedv_api.h index c6921ed2..a6684f13 100644 --- a/codec2-dev/src/freedv_api.h +++ b/codec2-dev/src/freedv_api.h @@ -34,85 +34,44 @@ #ifndef __FREEDV__ +// This declares a single-precision (float) complex number +#include "comp.h" + #define FREEDV_MODE_1600 0 #define FREEDV_MODE_700 1 -#include "varicode.h" -#include "codec2_fdmdv.h" -#include "codec2_cohpsk.h" - -struct freedv { - int mode; - - struct CODEC2 *codec2; - struct FDMDV *fdmdv; - struct MODEM_STATS stats; - struct COHPSK *cohpsk; - - int n_speech_samples; - int n_nom_modem_samples; // size of tx and most rx modem sample buffers - int n_max_modem_samples; // make your rx modem sample buffers this big - - int modem_sample_rate; // ATM caller is responsible for meeting this (TBC) - int clip; // non-zero for cohpsk modem output clipping for low PAPR - - unsigned char *packed_codec_bits; - int *codec_bits; - int *tx_bits; - int *fdmdv_bits; - int *rx_bits; - int tx_sync_bit; - int smooth_symbols; - float *prev_rx_bits; - - int *ptest_bits_coh; - int *ptest_bits_coh_end; - - int test_frames; // set this baby for 1 to tx/rx test frames to look at bit error stats - int test_frame_sync_state; - int test_frame_count; - int total_bits; - int total_bit_errors; - int sz_error_pattern; - - /* optional user defined function to pass error pattern when a test frame is received */ +struct freedv; - void *error_pattern_callback_state; - void (*freedv_put_error_pattern)(void *error_pattern_callback_state, short error_pattern[], int sz_error_pattern); - - int sync; - int evenframe; - float snr_est; - float snr_squelch_thresh; - float squelch_en; - int nin; - - struct VARICODE_DEC varicode_dec_states; - short tx_varicode_bits[VARICODE_MAX_BITS]; - int nvaricode_bits; - int varicode_bit_index; - - /* user defined function ptrs to produce and consume ASCII - characters using aux txt channel */ - - char (*freedv_get_next_tx_char)(void *callback_state); - void (*freedv_put_next_rx_char)(void *callback_state, char c); - - void *callback_state; - -}; +typedef void (*freedv_callback_rx)(void *, char); +typedef char (*freedv_callback_tx)(void *); +// FreeDV API functions: +// open, close struct freedv *freedv_open(int mode); void freedv_close(struct freedv *freedv); - -void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]); -void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]); - -int freedv_nin(struct freedv *f); -int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]); -int freedv_floatrx(struct freedv *f, short speech_out[], float demod_in[]); -int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]); - +// Transmit +void freedv_tx(struct freedv *freedv, short mod_out[], short speech_in[]); +void freedv_comptx(struct freedv *freedv, COMP mod_out[], short speech_in[]); +// Receive +int freedv_nin(struct freedv *freedv); +int freedv_rx(struct freedv *freedv, short speech_out[], short demod_in[]); +int freedv_floatrx(struct freedv *freedv, short speech_out[], float demod_in[]); +int freedv_comprx(struct freedv *freedv, short speech_out[], COMP demod_in[]); +// Set parameters +void freedv_set_callback_txt(struct freedv *freedv, freedv_callback_rx rx, freedv_callback_tx tx, void *callback_state); +void freedv_set_test_frames (struct freedv *freedv, int test_frames); +void freedv_set_smooth_symbols (struct freedv *freedv, int smooth_symbols); +void freedv_set_squelch_en (struct freedv *freedv, int squelch_en); +void freedv_set_snr_squelch_thresh (struct freedv *freedv, float snr_squelch_thresh); +// Get parameters +int freedv_get_version(void); +void freedv_get_modem_stats(struct freedv *freedv, int *sync, float *snr_est); +int freedv_get_test_frames (struct freedv *freedv); +int freedv_get_n_speech_samples (struct freedv *freedv); +int freedv_get_n_max_modem_samples (struct freedv *freedv); +int freedv_get_n_nom_modem_samples (struct freedv *freedv); +int freedv_get_total_bits (struct freedv *freedv); +int freedv_get_total_bit_errors (struct freedv *freedv); #endif #ifdef __cplusplus diff --git a/codec2-dev/src/freedv_rx.c b/codec2-dev/src/freedv_rx.c index c24d34c8..28a920ee 100644 --- a/codec2-dev/src/freedv_rx.c +++ b/codec2-dev/src/freedv_rx.c @@ -60,6 +60,12 @@ int main(int argc, char *argv[]) { int nin, nout, frame = 0; struct my_callback_state my_cb_state; int mode; + int sync; + int total_bits; + int total_bit_errors; + float snr_est; + int n_speech_samples; + int n_max_modem_samples; if (argc < 4) { printf("usage: %s 1600|700 InputModemSpeechFile OutputSpeechRawFile [--test_frames]\n", argv[0]); @@ -92,21 +98,22 @@ int main(int argc, char *argv[]) { assert(freedv != NULL); if ( (argc > 4) && (strcmp(argv[4], "--testframes") == 0) ) { - freedv->test_frames = 1; + freedv_set_test_frames(freedv, 1); } + freedv_set_snr_squelch_thresh(freedv, -100.0); + freedv_set_squelch_en(freedv, 1); - speech_out = (short*)malloc(sizeof(short)*freedv->n_speech_samples); + n_speech_samples = freedv_get_n_speech_samples(freedv); + n_max_modem_samples = freedv_get_n_max_modem_samples(freedv); + speech_out = (short*)malloc(sizeof(short)*n_speech_samples); assert(speech_out != NULL); - demod_in = (short*)malloc(sizeof(short)*freedv->n_max_modem_samples); + demod_in = (short*)malloc(sizeof(short)*n_max_modem_samples); assert(demod_in != NULL); ftxt = fopen("freedv_rx_log.txt","wt"); assert(ftxt != NULL); my_cb_state.ftxt = ftxt; - freedv->callback_state = (void*)&my_cb_state; - freedv->freedv_put_next_rx_char = &my_put_next_rx_char; - - freedv->snr_squelch_thresh = -100.0; + freedv_set_callback_txt(freedv, &my_put_next_rx_char, NULL, &my_cb_state); /* Note we need to work out how many samples demod needs on each call (nin). This is used to adjust for differences in the tx and rx @@ -121,12 +128,14 @@ int main(int argc, char *argv[]) { nin = freedv_nin(freedv); fwrite(speech_out, sizeof(short), nout, fout); + freedv_get_modem_stats(freedv, &sync, &snr_est); + total_bit_errors = freedv_get_total_bit_errors(freedv); /* log some side info to the txt file */ if (ftxt != NULL) { fprintf(ftxt, "frame: %d demod sync: %d demod snr: %3.2f dB bit errors: %d\n", frame, - freedv->sync, freedv->snr_est, freedv->total_bit_errors); + sync, snr_est, total_bit_errors); } /* if this is in a pipeline, we probably don't want the usual @@ -136,8 +145,10 @@ int main(int argc, char *argv[]) { if (fin == stdin) fflush(stdin); } - if (freedv->test_frames) { - fprintf(stderr, "bits: %d errors: %d BER: %3.2f\n", freedv->total_bits, freedv->total_bit_errors, (float)freedv->total_bit_errors/freedv->total_bits); + if (freedv_get_test_frames(freedv)) { + total_bits = freedv_get_total_bits(freedv); + total_bit_errors = freedv_get_total_bit_errors(freedv); + fprintf(stderr, "bits: %d errors: %d BER: %3.2f\n", total_bits, total_bit_errors, (float)total_bit_errors/total_bits); } free(speech_out); diff --git a/codec2-dev/src/freedv_tx.c b/codec2-dev/src/freedv_tx.c index 80e4c479..a3279229 100644 --- a/codec2-dev/src/freedv_tx.c +++ b/codec2-dev/src/freedv_tx.c @@ -56,6 +56,8 @@ int main(int argc, char *argv[]) { struct freedv *freedv; struct my_callback_state my_cb_state; int mode; + int n_speech_samples; + int n_nom_modem_samples; if (argc < 4) { printf("usage: %s 1600|700 InputRawSpeechFile OutputModemRawFile [--testframes]\n", argv[0]); @@ -88,26 +90,29 @@ int main(int argc, char *argv[]) { assert(freedv != NULL); if ((argc > 4) && (strcmp(argv[4], "--testframes") == 0)) { - freedv->test_frames = 1; + freedv_set_test_frames(freedv, 1); } + freedv_set_snr_squelch_thresh(freedv, -100.0); + freedv_set_squelch_en(freedv, 1); - speech_in = (short*)malloc(sizeof(short)*freedv->n_speech_samples); + n_speech_samples = freedv_get_n_speech_samples(freedv); + n_nom_modem_samples = freedv_get_n_nom_modem_samples(freedv); + speech_in = (short*)malloc(sizeof(short)*n_speech_samples); assert(speech_in != NULL); - mod_out = (short*)malloc(sizeof(short)*freedv->n_nom_modem_samples); + mod_out = (short*)malloc(sizeof(short)*n_nom_modem_samples); assert(mod_out != NULL); /* set up callback for txt msg chars */ sprintf(my_cb_state.tx_str, "cq cq cq hello world\n"); my_cb_state.ptx_str = my_cb_state.tx_str; - freedv->callback_state = (void*)&my_cb_state; - freedv->freedv_get_next_tx_char = &my_get_next_tx_char; + freedv_set_callback_txt(freedv, NULL, &my_get_next_tx_char, &my_cb_state); /* OK main loop */ - while(fread(speech_in, sizeof(short), freedv->n_speech_samples, fin) == freedv->n_speech_samples) { + while(fread(speech_in, sizeof(short), n_speech_samples, fin) == n_speech_samples) { freedv_tx(freedv, mod_out, speech_in); - fwrite(mod_out, sizeof(short), freedv->n_nom_modem_samples, fout); + fwrite(mod_out, sizeof(short), n_nom_modem_samples, fout); /* if this is in a pipeline, we probably don't want the usual buffering to occur */ -- 2.25.1