#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 */
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
+
#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
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]);
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
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
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);
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]);
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 */