#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <math.h>
#include "codec2.h"
#include "codec2_fdmdv.h"
+#include "fdmdv_internal.h"
#include "golay23.h"
#include "varicode.h"
#include "freedv_api.h"
+#include "comp_prim.h"
/*---------------------------------------------------------------------------*\
struct freedv *f;
int Nc, codec2_mode, nbit, nbyte;
- if (mode != FREEDV_MODE_1600)
+ if ((mode != FREEDV_MODE_1600) && (mode != FREEDV_MODE_700))
return NULL;
-
+
f = (struct freedv*)malloc(sizeof(struct freedv));
if (f == NULL)
return NULL;
-
+
f->mode = mode;
- f->tx_sync_bit = 0;
- f->snr_thresh = 2.0;
-
+
if (mode == FREEDV_MODE_1600) {
Nc = 16;
+ f->tx_sync_bit = 0;
codec2_mode = CODEC2_MODE_1300;
+ f->fdmdv = fdmdv_create(Nc);
+ if (f->fdmdv == NULL)
+ return NULL;
+ f->snr_thresh = 2.0;
+ golay23_init();
+ f->nin = FDMDV_NOM_SAMPLES_PER_FRAME;
+ f->n_nom_modem_samples = 2*FDMDV_NOM_SAMPLES_PER_FRAME;
+ f->n_max_modem_samples = FDMDV_NOM_SAMPLES_PER_FRAME+FDMDV_MAX_SAMPLES_PER_FRAME;
+ f->modem_sample_rate = FS;
+ nbit = fdmdv_bits_per_frame(f->fdmdv);
+ f->fdmdv_bits = (int*)malloc(nbit*sizeof(int));
+ if (f->fdmdv_bits == NULL)
+ return NULL;
+ nbit = 2*fdmdv_bits_per_frame(f->fdmdv);
+ f->tx_bits = (int*)malloc(nbit*sizeof(int));
+ f->rx_bits = (int*)malloc(nbit*sizeof(int));
+ if ((f->tx_bits == NULL) || (f->rx_bits == NULL))
+ return NULL;
+ }
+
+ if (mode == FREEDV_MODE_700) {
+ codec2_mode = CODEC2_MODE_700;
+ f->cohpsk = cohpsk_create();
+ f->nin = COHPSK_NOM_SAMPLES_PER_FRAME;
+ f->n_nom_modem_samples = COHPSK_NOM_SAMPLES_PER_FRAME;
+ f->n_max_modem_samples = COHPSK_MAX_SAMPLES_PER_FRAME;
+ f->modem_sample_rate = COHPSK_FS; /* note wierd sample rate */
+ f->clip = 1;
+ nbit = COHPSK_BITS_PER_FRAME;
+ f->tx_bits = (int*)malloc(nbit*sizeof(int));
+ if (f->tx_bits == NULL)
+ return NULL;
}
f->codec2 = codec2_create(codec2_mode);
if (f->codec2 == NULL)
return NULL;
-
- f->fdmdv = fdmdv_create(Nc);
- if (f->fdmdv == NULL)
- return NULL;
+ if (mode == FREEDV_MODE_1600)
+ f->n_speech_samples = codec2_samples_per_frame(f->codec2);
+ if (mode == FREEDV_MODE_700)
+ f->n_speech_samples = 2*codec2_samples_per_frame(f->codec2);
nbit = codec2_bits_per_frame(f->codec2);
nbyte = (nbit + 7) / 8;
f->packed_codec_bits = (unsigned char*)malloc(nbyte*sizeof(char));
- f->codec_bits = (int*)malloc(nbit*sizeof(int));
+ if (mode == FREEDV_MODE_1600)
+ f->codec_bits = (int*)malloc(nbit*sizeof(int));
+ if (mode == FREEDV_MODE_700)
+ f->codec_bits = (int*)malloc(COHPSK_BITS_PER_FRAME*sizeof(int));
- nbit = 2*fdmdv_bits_per_frame(f->fdmdv);
- f->tx_bits = (int*)malloc(nbit*sizeof(int));
- f->rx_bits = (int*)malloc(nbit*sizeof(int));
-
- nbit = fdmdv_bits_per_frame(f->fdmdv);
- f->fdmdv_bits = (int*)malloc(nbit*sizeof(int));
-
- if ((f->packed_codec_bits == NULL) || (f->codec_bits == NULL)
- || (f->tx_bits == NULL) || (f->rx_bits == NULL) || (f->fdmdv_bits == NULL))
+ if ((f->packed_codec_bits == NULL) || (f->codec_bits == NULL))
return NULL;
varicode_decode_init(&f->varicode_dec_states, 1);
f->freedv_get_next_tx_char = NULL;
f->freedv_put_next_rx_char = NULL;
- golay23_init();
f->total_bit_errors = 0;
- f->nin = FDMDV_NOM_SAMPLES_PER_FRAME;
-
return f;
}
\*---------------------------------------------------------------------------*/
void freedv_close(struct freedv *freedv) {
+ assert(freedv != NULL);
+
free(freedv->packed_codec_bits);
free(freedv->codec_bits);
free(freedv->tx_bits);
- fdmdv_destroy(freedv->fdmdv);
+ if (freedv->mode == FREEDV_MODE_1600)
+ fdmdv_destroy(freedv->fdmdv);
+ if (freedv->mode == FREEDV_MODE_700)
+ cohpsk_destroy(freedv->cohpsk);
codec2_destroy(freedv->codec2);
free(freedv);
}
Takes a frame of input speech samples, encodes and modulates them to produce
a frame of modem samples that can be sent to the transmitter.
- speech_in[] and mod_out[] are sampled at 8 kHz, 16 bit shorts, and
- are always FREEDV_NSAMPLES long. The speech_in[] level should be
- such that the peak speech level is between +/16384 and +/- 32767.
- mod_out[] will be scaled such that the peak level is just less than
- +/-32767.
+ speech_in[] is sampled at 8 kHz, the user must supply
+ f->n_speech_samples. The speech_in[] level should be such that the
+ peak speech level is between +/16384 and +/- 32767.
- The FDM modem signal mod_out[] has a high crest factor (around
- 12dB), however the energy and duration of the peaks is small.
- FreeDV is generally operated at a "backoff" of 6-8dB. Adjust the
- power amplifier drive so that the average power is 6-8dB less than
- the peak power of the PA. For example, on a radio rated at 100W PEP
- for SSB, the average FreeDV power is typically 20-25W.
+ The FDM modem signal mod_out[] is sampled at f->modem_sample_rate
+ and is f->n_modem_samples long. mod_out[] will be scaled such that
+ the peak level is just less than +/-32767.
+
+ The FreeDV 1600 modem has a high crest factor (around 12dB), however
+ the energy and duration of the peaks is small. FreeDV 1600 is
+ usually operated at a "backoff" of 8dB. Adjust the power
+ amplifier drive so that the average power is 8dB less than the
+ peak power of the PA. For example, on a radio rated at 100W PEP for
+ SSB, the average FreeDV power is typically 20W.
+
+ The FreeDV 900 modem has a crest factor of about 5dB (with f->clip=1, the
+ default), so if your PA can handle it, it can be driven harder than
+ FreeDV 1600. Caution - some PAs cannot handle a high continuous
+ power. A conservative level is 20W average for a 100W PEP rated PA.
\*---------------------------------------------------------------------------*/
+/* real-valued short sample output, useful for going straight to DAC */
+
void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]) {
- int bit, byte, i, j;
- int bits_per_codec_frame, bits_per_fdmdv_frame;
+ assert(f != NULL);
+ COMP tx_fdm[f->n_nom_modem_samples];
+ int i;
+
+ freedv_comptx(f, tx_fdm, speech_in);
+
+ for(i=0; i<f->n_nom_modem_samples; i++)
+ mod_out[i] = tx_fdm[i].real;
+}
+
+/* complex valued output, useful for suitable for single sided freq shifting */
+
+void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]) {
+ assert(f != NULL);
+ int bit, byte, i, j, k;
+ int bits_per_codec_frame, bits_per_modem_frame;
int data, codeword1, data_flag_index;
- COMP tx_fdm[2*FDMDV_NOM_SAMPLES_PER_FRAME];
+ COMP tx_fdm[f->n_nom_modem_samples];
- bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
- bits_per_fdmdv_frame = fdmdv_bits_per_frame(f->fdmdv);
+ assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700));
+
+ if (f->mode == FREEDV_MODE_1600) {
+ bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
+ bits_per_modem_frame = fdmdv_bits_per_frame(f->fdmdv);
- codec2_encode(f->codec2, f->packed_codec_bits, speech_in);
+ codec2_encode(f->codec2, f->packed_codec_bits, speech_in);
- /* unpack bits, MSB first */
+ /* unpack bits, MSB first */
- bit = 7; byte = 0;
- for(i=0; i<bits_per_codec_frame; i++) {
- f->codec_bits[i] = (f->packed_codec_bits[byte] >> bit) & 0x1;
- bit--;
- if (bit < 0) {
- bit = 7;
- byte++;
+ bit = 7; byte = 0;
+ for(i=0; i<bits_per_codec_frame; i++) {
+ f->codec_bits[i] = (f->packed_codec_bits[byte] >> bit) & 0x1;
+ bit--;
+ if (bit < 0) {
+ bit = 7;
+ byte++;
+ }
}
- }
- // spare bit in frame that codec defines. Use this 1
- // bit/frame to send txt messages
+ // spare bit in frame that codec defines. Use this 1
+ // bit/frame to send txt messages
- data_flag_index = codec2_get_spare_bit_index(f->codec2);
+ data_flag_index = codec2_get_spare_bit_index(f->codec2);
- if (f->nvaricode_bits) {
- f->codec_bits[data_flag_index] = f->tx_varicode_bits[f->varicode_bit_index++];
- f->nvaricode_bits--;
- }
+ if (f->nvaricode_bits) {
+ f->codec_bits[data_flag_index] = f->tx_varicode_bits[f->varicode_bit_index++];
+ f->nvaricode_bits--;
+ }
- if (f->nvaricode_bits == 0) {
- /* get new char and encode */
- char s[2];
- if (f->freedv_get_next_tx_char != NULL) {
- s[0] = (*f->freedv_get_next_tx_char)(f->callback_state);
- f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1);
- f->varicode_bit_index = 0;
+ if (f->nvaricode_bits == 0) {
+ /* get new char and encode */
+ char s[2];
+ if (f->freedv_get_next_tx_char != NULL) {
+ s[0] = (*f->freedv_get_next_tx_char)(f->callback_state);
+ f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1);
+ f->varicode_bit_index = 0;
+ }
}
- }
- if (f->mode == FREEDV_MODE_1600) {
-
/* Protect first 12 out of first 16 excitation bits with (23,12) Golay Code:
0,1,2,3: v[0]..v[1]
f->tx_bits[i] = (codeword1 >> (10-j)) & 0x1;
}
f->tx_bits[i] = 0; /* spare bit */
+
+ /* modulate even and odd frames */
+
+ fdmdv_mod(f->fdmdv, tx_fdm, f->tx_bits, &f->tx_sync_bit);
+ assert(f->tx_sync_bit == 1);
+
+ fdmdv_mod(f->fdmdv, &tx_fdm[FDMDV_NOM_SAMPLES_PER_FRAME], &f->tx_bits[bits_per_modem_frame], &f->tx_sync_bit);
+ assert(f->tx_sync_bit == 0);
+
+ assert(2*FDMDV_NOM_SAMPLES_PER_FRAME == f->n_nom_modem_samples);
- //for(i=0; i<bits_per_codec_frame+12; i++)
- // printf("%d\n", f->tx_bits[i]);
+ for(i=0; i<f->n_nom_modem_samples; i++)
+ mod_out[i] = fcmult(FDMDV_SCALE, tx_fdm[i]);
}
- /* modulate even and odd frames */
- fdmdv_mod(f->fdmdv, tx_fdm, f->tx_bits, &f->tx_sync_bit);
- assert(f->tx_sync_bit == 1);
+ if (f->mode == FREEDV_MODE_700) {
+ bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
+ bits_per_modem_frame = COHPSK_BITS_PER_FRAME;
- fdmdv_mod(f->fdmdv, &tx_fdm[FDMDV_NOM_SAMPLES_PER_FRAME], &f->tx_bits[bits_per_fdmdv_frame], &f->tx_sync_bit);
- assert(f->tx_sync_bit == 0);
+ for (j=0; j<bits_per_modem_frame; j+=bits_per_codec_frame) {
+ codec2_encode(f->codec2, f->packed_codec_bits, speech_in);
+ speech_in += codec2_samples_per_frame(f->codec2);
- for(i=0; i<2*FDMDV_NOM_SAMPLES_PER_FRAME; i++)
- mod_out[i] = FDMDV_SCALE * tx_fdm[i].real;
+ /* unpack bits, MSB first */
+
+ bit = 7; byte = 0;
+ for(i=0; i<bits_per_codec_frame; i++) {
+ f->codec_bits[j+i] = (f->packed_codec_bits[byte] >> bit) & 0x1;
+ bit--;
+ if (bit < 0) {
+ bit = 7;
+ byte++;
+ }
+ }
+
+ // spare bits in frame that codec defines. Use these 2
+ // bits/frame to send txt messages
- assert(2*FDMDV_NOM_SAMPLES_PER_FRAME == FREEDV_NSAMPLES);
+ data_flag_index = codec2_get_spare_bit_index(f->codec2);
+
+ for(k=0; k<2; k++) {
+ if (f->nvaricode_bits) {
+ f->codec_bits[j+data_flag_index+k] = f->tx_varicode_bits[f->varicode_bit_index++];
+ //fprintf(stderr, "%d %d\n", j+data_flag_index+k, f->codec_bits[j+data_flag_index+k]);
+ f->nvaricode_bits--;
+ }
+
+ if (f->nvaricode_bits == 0) {
+ /* get new char and encode */
+ char s[2];
+ if (f->freedv_get_next_tx_char != NULL) {
+ s[0] = (*f->freedv_get_next_tx_char)(f->callback_state);
+ f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1);
+ f->varicode_bit_index = 0;
+ }
+ }
+ }
+
+ }
+
+ /* cohpsk modulator */
+
+ cohpsk_mod(f->cohpsk, tx_fdm, f->codec_bits);
+ if (f->clip)
+ cohpsk_clip(tx_fdm);
+ for(i=0; i<f->n_nom_modem_samples; i++)
+ mod_out[i] = fcmult(FDMDV_SCALE, tx_fdm[i]);
+ }
}
int freedv_nin(struct freedv *f) {
samples. Call freedv_nin() before each call to freedv_rx() to
determine how many samples to pass to this function (see example).
+ The maximum vlaue of freedv_nin is set by f->n_max_modem_samples,
+ allocate this much storage to your buffers.
+
Returns the number of output speech samples available in
speech_out[]. When in sync this will typically alternate between 0
- and FREEDV_NSAMPLES. When out of sync, this will be f->nin.
+ and f->n_speech_samples. When out of sync, this will be f->nin.
When out of sync, this function echoes the demod_in[] samples to
speech_out[]. This allows the user to listen to the channel, which
\*---------------------------------------------------------------------------*/
+
// short version
int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) {
-
- float rxdata[FDMDV_MAX_SAMPLES_PER_FRAME];
+ assert(f != NULL);
+ COMP rx_fdm[f->n_max_modem_samples];
int i;
- for(i=0; i<f->nin; i++)
- rxdata[i] = (float)demod_in[i]/FDMDV_SCALE;
+ assert(f->nin <= f->n_max_modem_samples);
- return freedv_floatrx(f, speech_out, rxdata);
-
+ for(i=0; i<f->nin; i++) {
+ rx_fdm[i].real = (float)demod_in[i];
+ rx_fdm[i].imag = 0.0;
+ }
+
+ return freedv_comprx(f, speech_out, rx_fdm);
}
// float input samples version
int freedv_floatrx(struct freedv *f, short speech_out[], float demod_in[]) {
- COMP rx_fdm[FDMDV_MAX_SAMPLES_PER_FRAME];
+ assert(f != NULL);
+ COMP rx_fdm[f->n_max_modem_samples];
int i;
+ assert(f->nin <= f->n_max_modem_samples);
+
for(i=0; i<f->nin; i++) {
rx_fdm[i].real = demod_in[i];
rx_fdm[i].imag = 0;
// complex input samples version
int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) {
+ assert(f != NULL);
int bits_per_codec_frame, bytes_per_codec_frame, bits_per_fdmdv_frame;
- int reliable_sync_bit, i, j, bit, byte, nin_prev, nout;
+ int reliable_sync_bit, i, j, bit, byte, nin_prev, nout, k;
int recd_codeword, codeword1, data_flag_index, n_ascii;
short abit[1];
char ascii_out;
+ assert(f->nin <= f->n_max_modem_samples);
+
+ for(i=0; i<f->nin; i++)
+ demod_in[i] = fcmult(1.0/FDMDV_SCALE, demod_in[i]);
+
bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
- bits_per_fdmdv_frame = fdmdv_bits_per_frame(f->fdmdv);
- nin_prev = f->nin;
- fdmdv_demod(f->fdmdv, f->fdmdv_bits, &reliable_sync_bit, demod_in, &f->nin);
- fdmdv_get_demod_stats(f->fdmdv, &f->fdmdv_stats);
+ if (f->mode == FREEDV_MODE_1600) {
+ bits_per_fdmdv_frame = fdmdv_bits_per_frame(f->fdmdv);
- if (f->fdmdv_stats.sync) {
- if (reliable_sync_bit == 0) {
- memcpy(f->rx_bits, f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int));
- nout = 0;
- }
- else {
- memcpy(&f->rx_bits[bits_per_fdmdv_frame], f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int));
+ nin_prev = f->nin;
+ fdmdv_demod(f->fdmdv, f->fdmdv_bits, &reliable_sync_bit, demod_in, &f->nin);
+ fdmdv_get_demod_stats(f->fdmdv, &f->fdmdv_stats);
+
+ if (f->fdmdv_stats.sync) {
+ if (reliable_sync_bit == 0) {
+ memcpy(f->rx_bits, f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int));
+ nout = 0;
+ }
+ else {
+ memcpy(&f->rx_bits[bits_per_fdmdv_frame], f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int));
- if (f->mode == FREEDV_MODE_1600) {
- recd_codeword = 0;
- for(i=0; i<8; i++) {
- recd_codeword <<= 1;
- recd_codeword |= (f->rx_bits[i] & 0x1);
- }
- for(i=11; i<15; i++) {
- recd_codeword <<= 1;
- recd_codeword |= (f->rx_bits[i] & 0x1);
- }
- for(i=bits_per_codec_frame; i<bits_per_codec_frame+11; i++) {
- recd_codeword <<= 1;
- recd_codeword |= (f->rx_bits[i] & 0x1);
- }
- codeword1 = golay23_decode(recd_codeword);
- f->total_bit_errors += golay23_count_errors(recd_codeword, codeword1);
+ if (f->mode == FREEDV_MODE_1600) {
+ recd_codeword = 0;
+ for(i=0; i<8; i++) {
+ recd_codeword <<= 1;
+ recd_codeword |= (f->rx_bits[i] & 0x1);
+ }
+ for(i=11; i<15; i++) {
+ recd_codeword <<= 1;
+ recd_codeword |= (f->rx_bits[i] & 0x1);
+ }
+ for(i=bits_per_codec_frame; i<bits_per_codec_frame+11; i++) {
+ recd_codeword <<= 1;
+ recd_codeword |= (f->rx_bits[i] & 0x1);
+ }
+ codeword1 = golay23_decode(recd_codeword);
+ f->total_bit_errors += golay23_count_errors(recd_codeword, codeword1);
- //codeword1 = recd_codeword;
- //fprintf(stderr, "received codeword1: 0x%x decoded codeword1: 0x%x\n", recd_codeword, codeword1);
+ //codeword1 = recd_codeword;
+ //fprintf(stderr, "received codeword1: 0x%x decoded codeword1: 0x%x\n", recd_codeword, codeword1);
- for(i=0; i<bits_per_codec_frame; i++)
- f->codec_bits[i] = f->rx_bits[i];
+ for(i=0; i<bits_per_codec_frame; i++)
+ f->codec_bits[i] = f->rx_bits[i];
- for(i=0; i<8; i++) {
- f->codec_bits[i] = (codeword1 >> (22-i)) & 0x1;
+ for(i=0; i<8; i++) {
+ f->codec_bits[i] = (codeword1 >> (22-i)) & 0x1;
+ }
+ for(i=8,j=11; i<12; i++,j++) {
+ f->codec_bits[j] = (codeword1 >> (22-i)) & 0x1;
+ }
}
- for(i=8,j=11; i<12; i++,j++) {
- f->codec_bits[j] = (codeword1 >> (22-i)) & 0x1;
+
+ // extract txt msg data bit ------------------------------------------------------------
+
+ data_flag_index = codec2_get_spare_bit_index(f->codec2);
+ abit[0] = f->codec_bits[data_flag_index];
+
+ n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, abit, 1, 1);
+ if (n_ascii && (f->freedv_put_next_rx_char != NULL)) {
+ (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out);
}
- }
- // extract txt msg data bit ------------------------------------------------------------
+ // reconstruct missing bit we steal for data bit and decode speech
- data_flag_index = codec2_get_spare_bit_index(f->codec2);
- abit[0] = f->codec_bits[data_flag_index];
+ codec2_rebuild_spare_bit(f->codec2, f->codec_bits);
- n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, abit, 1, 1);
- if (n_ascii && (f->freedv_put_next_rx_char != NULL)) {
- (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out);
- }
+ // pack bits, MSB received first
- // reconstruct missing bit we steal for data bit and decode speech
+ bit = 7;
+ byte = 0;
+ memset(f->packed_codec_bits, 0, bytes_per_codec_frame);
+ for(i=0; i<bits_per_codec_frame; i++) {
+ f->packed_codec_bits[byte] |= (f->codec_bits[i] << bit);
+ bit--;
+ if(bit < 0) {
+ bit = 7;
+ byte++;
+ }
+ }
- codec2_rebuild_spare_bit(f->codec2, f->codec_bits);
+ codec2_decode(f->codec2, speech_out, f->packed_codec_bits);
- // pack bits, MSB received first
+ /* squelch if beneath SNR threshold */
- bit = 7;
- byte = 0;
- memset(f->packed_codec_bits, 0, bytes_per_codec_frame);
- for(i=0; i<bits_per_codec_frame; i++) {
- f->packed_codec_bits[byte] |= (f->codec_bits[i] << bit);
- bit--;
- if(bit < 0) {
- bit = 7;
- byte++;
+ if (f->fdmdv_stats.snr_est < f->snr_thresh) {
+ for(i=0; i<f->n_speech_samples; i++)
+ speech_out[i] = 0;
}
+
+ nout = f->n_speech_samples;
}
+ } /* if (sync) .... */
+ else {
+ /* if not in sync pass through analog samples */
+ /* this lets us "hear" whats going on, e.g. during tuning */
+ for(i=0; i<nin_prev; i++)
+ speech_out[i] = FDMDV_SCALE*demod_in[i].real;
+ nout = nin_prev;
+ }
+ }
- codec2_decode(f->codec2, speech_out, f->packed_codec_bits);
- /* squelch if beneath SNR threshold */
+ if (f->mode == FREEDV_MODE_700) {
+ float rx_bits[COHPSK_BITS_PER_FRAME];
+ int reliable_sync_bit;
- if (f->fdmdv_stats.snr_est < f->snr_thresh) {
- for(i=0; i<FREEDV_NSAMPLES; i++)
- speech_out[i] = 0;
- }
+ nin_prev = f->nin;
+ cohpsk_demod(f->cohpsk, rx_bits, &reliable_sync_bit, demod_in, &f->nin);
+
+ if (reliable_sync_bit) {
- nout = FREEDV_NSAMPLES;
+ data_flag_index = codec2_get_spare_bit_index(f->codec2);
+
+ for (j=0; j<COHPSK_BITS_PER_FRAME; j+=bits_per_codec_frame) {
+
+ /* extract txt msg data bits */
+
+ for(k=0; k<2; k++) {
+ abit[0] = rx_bits[data_flag_index+j+k] < 0.0;
+
+ n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, abit, 1, 1);
+ if (n_ascii && (f->freedv_put_next_rx_char != NULL)) {
+ (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out);
+ }
+ }
+
+ /* pack bits, MSB received first */
+
+ bit = 7; byte = 0;
+ memset(f->packed_codec_bits, 0, bytes_per_codec_frame);
+ for(i=0; i<bits_per_codec_frame; i++) {
+ f->packed_codec_bits[byte] |= ((rx_bits[j+i] < 0.0) << bit);
+ bit--;
+ if (bit < 0) {
+ bit = 7;
+ byte++;
+ }
+ }
+
+ codec2_decode(f->codec2, speech_out, f->packed_codec_bits);
+ speech_out += codec2_samples_per_frame(f->codec2);
+ }
+ nout = f->n_speech_samples;
}
- } /* if (sync) .... */
- else {
- /* if not in sync pass through analog samples */
- /* this lets us "hear" whats going on, e.g. during tuning */
- for(i=0; i<nin_prev; i++)
- speech_out[i] = FDMDV_SCALE*demod_in[i].real;
- nout = nin_prev;
- }
+ else {
+ /* if not in sync pass through analog samples */
+ /* this lets us "hear" whats going on, e.g. during tuning */
+ for(i=0; i<nin_prev; i++)
+ speech_out[i] = FDMDV_SCALE*demod_in[i].real;
+ nout = nin_prev;
+ }
+ }
return nout;
}