Jeroen's DML patch, applied cleanly, code builds, but not tested
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Thu, 25 Feb 2016 09:36:05 +0000 (09:36 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Thu, 25 Feb 2016 09:36:05 +0000 (09:36 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@2708 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/src/freedv_api.c
codec2-dev/src/freedv_api.h
codec2-dev/src/freedv_api_internal.h

index 0ebd06bb9a4c3e2fac961ca8d5b178f5fe5a7819..d11564672c1577ecd6ab81812e9c06863b077796 100644 (file)
@@ -212,17 +212,22 @@ struct freedv *freedv_open(int mode) {
     f->codec2 = codec2_create(codec2_mode);
     if (f->codec2 == NULL)
         return NULL;
-    if ((mode == FREEDV_MODE_1600) || (mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B))
+    if ((mode == FREEDV_MODE_1600) || (mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B)) {
         f->n_speech_samples = codec2_samples_per_frame(f->codec2);
-    if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B))
+       f->n_codec_bits = codec2_bits_per_frame(f->codec2);
+        nbit = f->n_codec_bits;
+        nbyte = (nbit + 7) / 8;
+    } else { /* ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B)) */
         f->n_speech_samples = 2*codec2_samples_per_frame(f->codec2);
+       f->n_codec_bits = 2*codec2_bits_per_frame(f->codec2);
+        nbit = f->n_codec_bits;
+        nbyte = 2*((codec2_bits_per_frame(f->codec2) + 7) / 8);
+    }
     
     f->prev_rx_bits = (float*)malloc(sizeof(float)*2*codec2_bits_per_frame(f->codec2));
     if (f->prev_rx_bits == NULL)
         return NULL;
 
-    nbit = codec2_bits_per_frame(f->codec2);
-    nbyte = (nbit + 7) / 8;
     f->packed_codec_bits = (unsigned char*)malloc(nbyte*sizeof(char));
     if (mode == FREEDV_MODE_1600)
         f->codec_bits = (int*)malloc(nbit*sizeof(int));
@@ -338,12 +343,61 @@ void freedv_close(struct freedv *freedv) {
 
 /* real-valued short sample output, useful for going straight to DAC */
 
+/* TX routines for 2400 FSK modes, after codec2 encoding */
+static void freedv_tx_fsk(struct freedv *f, short mod_out[]) {
+    int  i;
+    float *tx_float; /* To hold on to modulated samps from fsk/fmfsk */
+    uint8_t vc_bits[2]; /* Varicode bits for 2400 framing */
+    
+        
+    /* Get varicode bits for TX and possibly ask for a new char */
+    /* 2 bits per 2400A/B frame, so this has to be done twice */
+    for(i=0;i<2;i++){
+        if (f->nvaricode_bits) {
+            vc_bits[i] = 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 the API user hasn't set up message callbacks, don't bother with varicode bits */
+    if(f->freedv_get_next_tx_char == NULL){
+        fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL);
+    }else{
+        fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,vc_bits);
+    }
+        
+    /* Allocate floating point buffer for FSK mod */
+    tx_float = alloca(sizeof(float)*f->n_nom_modem_samples);
+        
+    /* do 4fsk mod */
+    if(f->mode == FREEDV_MODE_2400A){
+        fsk_mod(f->fsk,tx_float,(uint8_t*)(f->tx_bits));
+        
+    /* do me-fsk mod */
+    }else if(f->mode == FREEDV_MODE_2400B){
+        fmfsk_mod(f->fmfsk,tx_float,(uint8_t*)(f->tx_bits));
+    }
+        
+    /* Convert float samps to short */
+    for(i=0; i<f->n_nom_modem_samples; i++){
+        mod_out[i] = (short)(tx_float[i]*FDMDV_SCALE);
+    }
+}
+
 void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]) {
     assert(f != NULL);
     COMP tx_fdm[f->n_nom_modem_samples];
     int  i;
-    float *tx_float; /* To hold on to modulated samps from fsk/fmfsk */
-    uint8_t vc_bits[2]; /* Varicode bits for 2400 framing */
     
     assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) || 
            (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_2400A) || 
@@ -355,48 +409,7 @@ void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]) {
     if((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B)){
         codec2_encode(f->codec2, f->packed_codec_bits, speech_in);
         
-        /* Get varicode bits for TX and possibly ask for a new char */
-        /* 2 bits per 2400A/B frame, so this has to be done twice */
-        for(i=0;i<2;i++){
-            if (f->nvaricode_bits) {
-                vc_bits[i] = 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 the API user hasn't set up message callbacks, don't bother with varicode bits */
-        if(f->freedv_get_next_tx_char == NULL){
-            fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL);
-        }else{
-            fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,vc_bits);
-        }
-        
-        /* Allocate floating point buffer for FSK mod */
-        tx_float = alloca(sizeof(float)*f->n_nom_modem_samples);
-        
-        /* do 4fsk mod */
-        if(f->mode == FREEDV_MODE_2400A){
-            fsk_mod(f->fsk,tx_float,(uint8_t*)(f->tx_bits));
-        
-        /* do me-fsk mod */
-        }else if(f->mode == FREEDV_MODE_2400B){
-            fmfsk_mod(f->fmfsk,tx_float,(uint8_t*)(f->tx_bits));
-        }
-        
-        /* Convert float samps to short */
-        for(i=0; i<f->n_nom_modem_samples; i++){
-            mod_out[i] = (short)(tx_float[i]*FDMDV_SCALE);
-        }
+       freedv_tx_fsk(f, mod_out);
     }else{
         freedv_comptx(f, tx_fdm, speech_in);
         for(i=0; i<f->n_nom_modem_samples; i++)
@@ -406,176 +419,204 @@ void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]) {
 
 /* 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;
+static void freedv_comptx_fdmdv_1600(struct freedv *f, COMP mod_out[]) {
+    int    bit, byte, i, j;
     int    bits_per_codec_frame, bits_per_modem_frame;
-    int    data, codeword1, data_flag_index, nspare;
+    int    data, codeword1, data_flag_index;
     COMP   tx_fdm[f->n_nat_modem_samples];
-    short  tx_real[f->n_nom_modem_samples];
 
-    assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) || 
-           (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_2400A) || 
-           (f->mode == FREEDV_MODE_2400B));
+    bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
+    bits_per_modem_frame = fdmdv_bits_per_frame(f->fdmdv);
 
-    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);
+    /* 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;
         }
+    }
 
-        /* Protect first 12 out of first 16 excitation bits with (23,12) Golay Code:
+    /* Protect first 12 out of first 16 excitation bits with (23,12) Golay Code:
 
-           0,1,2,3: v[0]..v[1]
-           4,5,6,7: MSB of pitch
-           11,12,13,14: MSB of energy
+       0,1,2,3: v[0]..v[1]
+       4,5,6,7: MSB of pitch
+       11,12,13,14: MSB of energy
 
-        */
+    */
 
-        data = 0;
-        for(i=0; i<8; i++) {
-            data <<= 1;
-            data |= f->codec_bits[i];
-        }
-        for(i=11; i<15; i++) {
-            data <<= 1;
-            data |= f->codec_bits[i];
-        }
-        codeword1 = golay23_encode(data);
+    data = 0;
+    for(i=0; i<8; i++) {
+        data <<= 1;
+        data |= f->codec_bits[i];
+    }
+    for(i=11; i<15; i++) {
+        data <<= 1;
+        data |= f->codec_bits[i];
+    }
+    codeword1 = golay23_encode(data);
 
-        /* now pack output frame with parity bits at end to make them
-           as far apart as possible from the data they protect.  Parity
-           bits are LSB of the Golay codeword */
+    /* now pack output frame with parity bits at end to make them
+       as far apart as possible from the data they protect.  Parity
+       bits are LSB of the Golay codeword */
 
-        for(i=0; i<bits_per_codec_frame; i++)
-            f->tx_bits[i] = f->codec_bits[i];
-        for(j=0; i<bits_per_codec_frame+11; i++,j++) {
-            f->tx_bits[i] = (codeword1 >> (10-j)) & 0x1;
-        }
-        f->tx_bits[i] = 0; /* spare bit */
+    for(i=0; i<bits_per_codec_frame; i++)
+        f->tx_bits[i] = f->codec_bits[i];
+    for(j=0; i<bits_per_codec_frame+11; i++,j++) {
+        f->tx_bits[i] = (codeword1 >> (10-j)) & 0x1;
+    }
+    f->tx_bits[i] = 0; /* spare bit */
 
-        /* optionally overwrite with test frames */
+    /* optionally overwrite with test frames */
 
-        if (f->test_frames) {
-            fdmdv_get_test_bits(f->fdmdv, f->tx_bits);
-            fdmdv_get_test_bits(f->fdmdv, &f->tx_bits[bits_per_modem_frame]);
-            //fprintf(stderr, "test frames on tx\n");
-        }
+    if (f->test_frames) {
+        fdmdv_get_test_bits(f->fdmdv, f->tx_bits);
+        fdmdv_get_test_bits(f->fdmdv, &f->tx_bits[bits_per_modem_frame]);
+        //fprintf(stderr, "test frames on tx\n");
+    }
 
-        /* modulate even and odd frames */
+    /* 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, 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);
+    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);
+    assert(2*FDMDV_NOM_SAMPLES_PER_FRAME == f->n_nom_modem_samples);
 
-        for(i=0; i<f->n_nom_modem_samples; i++)
-            mod_out[i] = fcmult(FDMDV_SCALE, tx_fdm[i]);
-    }
+    for(i=0; i<f->n_nom_modem_samples; i++)
+        mod_out[i] = fcmult(FDMDV_SCALE, tx_fdm[i]);
+}
 
+static void freedv_comptx_fdmdv_700(struct freedv *f, COMP mod_out[]) {
+    int    bit, byte, i, j, k;
+    int    bits_per_codec_frame, bits_per_modem_frame;
+    int    data_flag_index, nspare;
+    COMP   tx_fdm[f->n_nat_modem_samples];
 
-#ifndef CORTEX_M4
-    if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B)) {
-        bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
-        bits_per_modem_frame = COHPSK_BITS_PER_FRAME;
+    bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
+    bits_per_modem_frame = COHPSK_BITS_PER_FRAME;
 
-        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);
+    byte = 0;
+    for (j=0; j<bits_per_modem_frame; j+=bits_per_codec_frame) {
 
-            /* unpack bits, MSB first */
+        /* 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++;
-                }
+        bit = 7;
+        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++;
             }
+        }
+       if (bit != 7)
+           byte++;
 
-            // spare bits in frame that codec defines.  Use these spare
-            // bits/frame to send txt messages
+        // spare bits in frame that codec defines.  Use these spare
+        // bits/frame to send txt messages
 
-            if (f->mode == FREEDV_MODE_700)
-                nspare = 2;
-            else
-                nspare = 1; // Just one spare bit for FREEDV_MODE_700B
+        if (f->mode == FREEDV_MODE_700)
+            nspare = 2;
+        else
+            nspare = 1; // Just one spare bit for FREEDV_MODE_700B
 
-            data_flag_index = codec2_get_spare_bit_index(f->codec2);
+        data_flag_index = codec2_get_spare_bit_index(f->codec2);
 
-            for(k=0; k<nspare; 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--;
-                }
+        for(k=0; k<nspare; 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;
-                    }
+            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;
                 }
             }
-
         }
 
-        /* optionally ovwerwrite the codec bits with test frames */
+    }
 
-        if (f->test_frames) {
-            cohpsk_get_test_bits(f->cohpsk, f->codec_bits);
-        }
+    /* optionally ovwerwrite the codec bits with test frames */
+
+    if (f->test_frames) {
+        cohpsk_get_test_bits(f->cohpsk, f->codec_bits);
+    }
+
+    /* cohpsk modulator */
+
+    cohpsk_mod(f->cohpsk, tx_fdm, f->codec_bits);
+    if (f->clip)
+        cohpsk_clip(tx_fdm);
+    for(i=0; i<f->n_nat_modem_samples; i++)
+        mod_out[i] = fcmult(FDMDV_SCALE*NORM_PWR, tx_fdm[i]);
+    i = quisk_cfInterpDecim(mod_out, f->n_nat_modem_samples, f->ptFilter7500to8000, 16, 15);
+    //assert(i == f->n_nom_modem_samples);
+    // Caution: assert fails if f->n_nat_modem_samples * 16.0 / 15.0 is not an integer
+
+}
+
+void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]) {
+    assert(f != NULL);
+    int    i, j;
+    int    bits_per_codec_frame;
+    short  tx_real[f->n_nom_modem_samples];
+
+    assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) || 
+           (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_2400A) || 
+           (f->mode == FREEDV_MODE_2400B));
+
+    if (f->mode == FREEDV_MODE_1600) {
+
+        codec2_encode(f->codec2, f->packed_codec_bits, speech_in);
+
+        freedv_comptx_fdmdv_1600(f, mod_out);
+    }
 
-        /* cohpsk modulator */
 
-        cohpsk_mod(f->cohpsk, tx_fdm, f->codec_bits);
-        if (f->clip)
-            cohpsk_clip(tx_fdm);
-        for(i=0; i<f->n_nat_modem_samples; i++)
-            mod_out[i] = fcmult(FDMDV_SCALE*NORM_PWR, tx_fdm[i]);
-        i = quisk_cfInterpDecim(mod_out, f->n_nat_modem_samples, f->ptFilter7500to8000, 16, 15);
-        //assert(i == f->n_nom_modem_samples);
-        // Caution: assert fails if f->n_nat_modem_samples * 16.0 / 15.0 is not an integer
+#ifndef CORTEX_M4
+    if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B)) {
+        bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
+       int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
+       int codec_frames = f->n_codec_bits / bits_per_codec_frame;
+
+        for (j=0; j < codec_frames; j++) {
+            codec2_encode(f->codec2, f->packed_codec_bits + j * bytes_per_codec_frame, speech_in);
+            speech_in += codec2_samples_per_frame(f->codec2);
+        }
+       
+       freedv_comptx_fdmdv_700(f, mod_out);
     }
     /* 2400 A and B are handled by the real-mode TX */
     if((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B)){
@@ -589,6 +630,37 @@ void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]) {
 #endif
 }
 
+void freedv_codectx(struct freedv *f, short mod_out[], unsigned char *packed_codec_bits) {
+    assert(f != NULL);
+    COMP tx_fdm[f->n_nom_modem_samples];
+    int bits_per_codec_frame;
+    int bytes_per_codec_frame;
+    int codec_frames;
+    int  i;
+    bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
+    bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
+    codec_frames = f->n_codec_bits / bits_per_codec_frame;
+
+    memcpy(f->packed_codec_bits, packed_codec_bits, bytes_per_codec_frame * codec_frames);
+    
+    switch(f->mode) {
+        case FREEDV_MODE_700:
+       case FREEDV_MODE_700B:
+            freedv_comptx_fdmdv_700(f, tx_fdm);
+           break;
+       case FREEDV_MODE_1600:
+           freedv_comptx_fdmdv_1600(f, tx_fdm);
+           break;
+        case FREEDV_MODE_2400A:
+       case FREEDV_MODE_2400B:       
+            freedv_tx_fsk(f, mod_out);
+           return; /* output is already real */
+    }
+    /* convert complex to real */
+    for(i=0; i<f->n_nom_modem_samples; i++)
+        mod_out[i] = tx_fdm[i].real;
+}
+
 int freedv_nin(struct freedv *f) {
     if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B))
         // For mode 700, the input rate is 8000 sps, but the modem rate is 7500 sps
@@ -674,51 +746,71 @@ int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) {
 
 // float input samples version
 
+int freedv_floatrx_fsk_2400(struct freedv *f, float demod_in[], int *valid) {
+    uint8_t vc_bits[2];
+    short vc_bit;
+    int i;
+    int n_ascii;
+    char ascii_out;
+    
+    if(f->mode == FREEDV_MODE_2400A){
+        fsk_demod(f->fsk,(uint8_t*)f->tx_bits,demod_in);
+        f->nin = fsk_nin(f->fsk);
+    }else{            
+        fmfsk_demod(f->fmfsk,(uint8_t*)f->tx_bits,demod_in);
+        f->nin = fmfsk_nin(f->fmfsk);
+    }
+    /* TODO: Protocol and varicode bits */
+    if(fvhff_deframe_bits(f->deframer,f->packed_codec_bits,NULL,NULL,(uint8_t*)f->tx_bits)){
+        /* Decode varicode text */
+        for(i=0; i<2; i++){
+            /* Note: deframe_bits spits out bits in uint8_ts while varicode_decode expects shorts */
+            vc_bit = vc_bits[i];
+            n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, &vc_bit, 1, 1);
+            if (n_ascii && (f->freedv_put_next_rx_char != NULL)) {
+                (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out);
+            }
+        }
+        *valid = 1;
+        f->sync = 1;
+        f->stats.sync = 1;
+    } else {
+        /* Fill with silence */
+        *valid = 0;
+        f->sync = 0;
+        f->stats.sync = 0;
+    }
+    return f->n_speech_samples;
+}
+
 int freedv_floatrx(struct freedv *f, short speech_out[], float demod_in[]) {
     assert(f != NULL);
     COMP rx_fdm[f->n_max_modem_samples];
-    uint8_t vc_bits[2];
-    short vc_bit;
     int  i;
     int nin = freedv_nin(f);    
-    int n_ascii;
-    char ascii_out;
     
     assert(nin <= f->n_max_modem_samples);
     
     /* FSK RX happens in real floats, so demod for those goes here */
     if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ){
-        if(f->mode == FREEDV_MODE_2400A){
-            fsk_demod(f->fsk,(uint8_t*)f->tx_bits,demod_in);
-            f->nin = fsk_nin(f->fsk);
-        }else{            
-            fmfsk_demod(f->fmfsk,(uint8_t*)f->tx_bits,demod_in);
-            f->nin = fmfsk_nin(f->fmfsk);
-        }
-        /* TODO: Protocol bits */
-        if(fvhff_deframe_bits(f->deframer,f->packed_codec_bits,NULL,vc_bits,(uint8_t*)f->tx_bits)){
-            /* Decode varicode text */
-            for(i=0; i<2; i++){
-                /* Note: deframe_bits spits out bits in uint8_ts while varicode_decode expects shorts */
-                vc_bit = vc_bits[i];
-                n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, &vc_bit, 1, 1);
-                if (n_ascii && (f->freedv_put_next_rx_char != NULL)) {
-                    (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out);
-                }
-            }
-            /* Decode the codec data */
-            codec2_decode(f->codec2,speech_out,f->packed_codec_bits);
-            f->sync = 1;
-            f->stats.sync = 1;
-            
-            
-        } else {
-            /* Fill with silence */
-            for(i=0;i<f->n_speech_samples;i++){
+        int valid;
+       int nout = freedv_floatrx_fsk_2400(f, demod_in, &valid);
+       
+       if (valid == 0)
+            for (i = 0; i < nout; i++)
                 speech_out[i] = 0;
+        else if (valid < 0)
+            for (i = 0; i < nout; i++)
+               speech_out[i] = demod_in[i];
+        else {
+            int bits_per_codec_frame  = codec2_bits_per_frame(f->codec2);
+            int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
+            int frames = f->n_codec_bits / bits_per_codec_frame;
+            for (i = 0; i < frames; i++) {
+                codec2_decode(f->codec2, speech_out, f->packed_codec_bits + i * bytes_per_codec_frame);
+                speech_out += codec2_samples_per_frame(f->codec2);
             }
-            f->sync = 0;
-            f->stats.sync = 0;
+
         }
         return f->n_speech_samples;
     }else { 
@@ -733,299 +825,379 @@ int freedv_floatrx(struct freedv *f, short speech_out[], float demod_in[]) {
 
 // complex input samples version
 
-int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) {
-    assert(f != NULL);
+static int freedv_comprx_fdmdv_1600(struct freedv *f, COMP demod_in[], int *valid) {
     int                 bits_per_codec_frame, bytes_per_codec_frame, bits_per_fdmdv_frame;
-    int                 i, j, bit, byte, nin_prev, nout, k;
-    int                 recd_codeword, codeword1, data_flag_index, n_ascii, nspare;
+    int                 i, j, bit, byte, nin_prev, nout;
+    int                 recd_codeword, codeword1, data_flag_index, n_ascii;
     short               abit[1];
     char                ascii_out;
     int                 reliable_sync_bit;
 
-    assert(f->nin <= f->n_max_modem_samples);
-
     bits_per_codec_frame  = codec2_bits_per_frame(f->codec2);
     bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
     nout = f->n_speech_samples;
 
-    if (f->mode == FREEDV_MODE_1600) {
+    for(i=0; i<f->nin; i++)
+        demod_in[i] = fcmult(1.0/FDMDV_SCALE, demod_in[i]);
 
-        for(i=0; i<f->nin; i++)
-            demod_in[i] = fcmult(1.0/FDMDV_SCALE, demod_in[i]);
+    bits_per_fdmdv_frame  = fdmdv_bits_per_frame(f->fdmdv);
 
-        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->stats);
+    f->sync = f->fdmdv->sync;
+    f->snr_est = f->stats.snr_est;
 
-        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->stats);
-        f->sync = f->fdmdv->sync;
-        f->snr_est = f->stats.snr_est;
+    if (reliable_sync_bit == 1) {
+        f->evenframe = 1;
+    }
 
-        if (reliable_sync_bit == 1) {
-            f->evenframe = 1;
+    if (f->stats.sync) {
+        if (f->evenframe == 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->stats.sync) {
-            if (f->evenframe == 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->test_frames == 0) {
-                    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);
-                    f->total_bits       += 23;
+            if (f->test_frames == 0) {
+                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);
+                f->total_bits       += 23;
 
-                    //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=8,j=11; i<12; i++,j++) {
-                        f->codec_bits[j] = (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;
+                }
 
-                    // extract txt msg data bit ------------------------------------------------------------
+                // extract txt msg data bit ------------------------------------------------------------
 
-                    data_flag_index = codec2_get_spare_bit_index(f->codec2);
-                    abit[0] = f->codec_bits[data_flag_index];
+                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);
-                    }
+                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);
+                }
 
-                    // reconstruct missing bit we steal for data bit and decode speech
+                // reconstruct missing bit we steal for data bit and decode speech
 
-                    codec2_rebuild_spare_bit(f->codec2, f->codec_bits);
+                codec2_rebuild_spare_bit(f->codec2, f->codec_bits);
 
-                    // pack bits, MSB received first
+                // 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] |= (f->codec_bits[i] << bit);
-                        bit--;
-                        if(bit < 0) {
-                            bit = 7;
-                            byte++;
-                        }
+                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_decode(f->codec2, speech_out, f->packed_codec_bits);
                 }
-                else {
-                    int   test_frame_sync, bit_errors, ntest_bits, k;
-                    short error_pattern[fdmdv_error_pattern_size(f->fdmdv)];
+                *valid = 1;
+            }
+            else {
+                int   test_frame_sync, bit_errors, ntest_bits, k;
+                short error_pattern[fdmdv_error_pattern_size(f->fdmdv)];
 
-                    for(k=0; k<2; k++) {
-                        /* test frames, so lets sync up to the test frames and count any errors */
-                        fdmdv_put_test_bits(f->fdmdv, &test_frame_sync, error_pattern, &bit_errors, &ntest_bits, &f->rx_bits[k*bits_per_fdmdv_frame]);
+                for(k=0; k<2; k++) {
+                    /* test frames, so lets sync up to the test frames and count any errors */
+                    fdmdv_put_test_bits(f->fdmdv, &test_frame_sync, error_pattern, &bit_errors, &ntest_bits, &f->rx_bits[k*bits_per_fdmdv_frame]);
 
-                        if (test_frame_sync == 1) {
-                            f->test_frame_sync_state = 1;
-                            f->test_frame_count = 0;
-                        }
+                    if (test_frame_sync == 1) {
+                        f->test_frame_sync_state = 1;
+                        f->test_frame_count = 0;
+                    }
 
-                        if (f->test_frame_sync_state) {
-                            if (f->test_frame_count == 0) {
-                                f->total_bit_errors += bit_errors;
-                                f->total_bits += ntest_bits;
-                                if (f->freedv_put_error_pattern != NULL) {
-                                    (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, fdmdv_error_pattern_size(f->fdmdv));
-                                }
-                           }
-                            f->test_frame_count++;
-                            if (f->test_frame_count == 4)
-                                f->test_frame_count = 0;
+                    if (f->test_frame_sync_state) {
+                        if (f->test_frame_count == 0) {
+                            f->total_bit_errors += bit_errors;
+                            f->total_bits += ntest_bits;
+                            if (f->freedv_put_error_pattern != NULL) {
+                                (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, fdmdv_error_pattern_size(f->fdmdv));
+                            }
                         }
-
-                        //fprintf(stderr, "test_frame_sync: %d test_frame_sync_state: %d bit_errors: %d ntest_bits: %d\n",
-                        //        test_frame_sync, f->test_frame_sync_state, bit_errors, ntest_bits);
+                        f->test_frame_count++;
+                        if (f->test_frame_count == 4)
+                            f->test_frame_count = 0;
                     }
+
+                    //fprintf(stderr, "test_frame_sync: %d test_frame_sync_state: %d bit_errors: %d ntest_bits: %d\n",
+                    //        test_frame_sync, f->test_frame_sync_state, bit_errors, ntest_bits);
                 }
+            }
 
 
-                /* squelch if beneath SNR threshold or test frames enabled */
+            /* squelch if beneath SNR threshold or test frames enabled */
 
-                if ((f->squelch_en && (f->stats.snr_est < f->snr_squelch_thresh)) || f->test_frames) {
-                    //fprintf(stderr,"squelch %f %f !\n", f->stats.snr_est, f->snr_squelch_thresh);
-                    for(i=0; i<f->n_speech_samples; i++)
-                        speech_out[i] = 0;
-                }
+            if ((f->squelch_en && (f->stats.snr_est < f->snr_squelch_thresh)) || f->test_frames) {
+                //fprintf(stderr,"squelch %f %f !\n", f->stats.snr_est, f->snr_squelch_thresh);
+                *valid = 0;
+            }
 
-                nout = f->n_speech_samples;
+            nout = f->n_speech_samples;
 
-            }
+        }
 
-            /* note this freewheels if reliable sync dissapears on bad channels */
+        /* note this freewheels if reliable sync dissapears on bad channels */
 
-            if (f->evenframe)
-                f->evenframe = 0;
-            else
-                f->evenframe = 1;
-            //fprintf(stderr,"%d\n",  f->evenframe);
+        if (f->evenframe)
+            f->evenframe = 0;
+        else
+            f->evenframe = 1;
+        //fprintf(stderr,"%d\n",  f->evenframe);
 
-        } /* if (sync) .... */
-        else {
-            /* if not in sync pass through analog samples */
-            /* this lets us "hear" whats going on, e.g. during tuning */
+    } /* if (sync) .... */
+    else {
+        /* if not in sync pass through analog samples */
+        /* this lets us "hear" whats going on, e.g. during tuning */
 
-            //fprintf(stderr, "out of sync\n");
+        //fprintf(stderr, "out of sync\n");
 
-           if (f->squelch_en == 0) {
-                for(i=0; i<nin_prev; i++)
-                    speech_out[i] = FDMDV_SCALE*demod_in[i].real;
-            }
-            else {
-                for(i=0; i<nin_prev; i++)
-                    speech_out[i] = 0;
-             }
-            //fprintf(stderr, "%d %d %d\n", nin_prev, speech_out[0], speech_out[nin_prev-1]);
-            nout = nin_prev;
+        if (f->squelch_en == 0) {
+           *valid = -1;
+        }
+        else {
+           *valid = 0;
         }
+        //fprintf(stderr, "%d %d %d\n", nin_prev, speech_out[0], speech_out[nin_prev-1]);
+        nout = nin_prev;
     }
-
+    return nout;
+}
 
 #ifndef CORTEX_M4
-    if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B)) {
-        float rx_bits[COHPSK_BITS_PER_FRAME];
-        int   sync;
+static int freedv_comprx_fdmdv_700(struct freedv *f, COMP demod_in[], int *valid) {
+    int                 bits_per_codec_frame, bytes_per_codec_frame;
+    int                 i, j, bit, byte, nout, k;
+    int                 data_flag_index, n_ascii, nspare;
+    short               abit[1];
+    char                ascii_out;
+    float rx_bits[COHPSK_BITS_PER_FRAME];
+    int   sync;
+    int   frames;
 
-        // echo samples back out as default (say if sync not found)
+    bits_per_codec_frame  = codec2_bits_per_frame(f->codec2);
+    bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
+    frames = f->n_codec_bits / bits_per_codec_frame;
+    nout = f->n_speech_samples;
 
-        for(i=0; i<freedv_nin(f); i++)
-            speech_out[i] = demod_in[i].real;
+    // echo samples back out as default (say if sync not found)
+    *valid = -1;
 
-        i = quisk_cfInterpDecim(demod_in, freedv_nin(f), f->ptFilter8000to7500, 15, 16);
-        //if (i != f->nin)
-        //    printf("freedv_comprx decimation: input %d output %d\n", freedv_nin(f), i);
+    i = quisk_cfInterpDecim(demod_in, freedv_nin(f), f->ptFilter8000to7500, 15, 16);
+    //if (i != f->nin)
+    //    printf("freedv_comprx decimation: input %d output %d\n", freedv_nin(f), i);
 
-        for(i=0; i<f->nin; i++)
-            demod_in[i] = fcmult(1.0/FDMDV_SCALE, demod_in[i]);
+    for(i=0; i<f->nin; i++)
+        demod_in[i] = fcmult(1.0/FDMDV_SCALE, demod_in[i]);
 
-        nin_prev = f->nin;
-        cohpsk_demod(f->cohpsk, rx_bits, &sync, demod_in, &f->nin);
-        f->sync = sync;
-        cohpsk_get_demod_stats(f->cohpsk, &f->stats);
-        f->snr_est = f->stats.snr_est;
+    cohpsk_demod(f->cohpsk, rx_bits, &sync, demod_in, &f->nin);
+    f->sync = sync;
+    cohpsk_get_demod_stats(f->cohpsk, &f->stats);
+    f->snr_est = f->stats.snr_est;
 
-        if (sync) {
+    memset(f->packed_codec_bits, 0, bytes_per_codec_frame * frames);
 
-            if (f->test_frames == 0) {
-                data_flag_index = codec2_get_spare_bit_index(f->codec2);
+    if (sync) {
 
-                /* optional smoothing of codec symbols */
+        if (f->test_frames == 0) {
+            data_flag_index = codec2_get_spare_bit_index(f->codec2);
 
-                if (f->smooth_symbols) {
+            /* optional smoothing of codec symbols */
 
-                    for(i=0; i<bits_per_codec_frame; i++) {
-                        rx_bits[i] += rx_bits[i+bits_per_codec_frame];
-                        rx_bits[i+bits_per_codec_frame] = rx_bits[i];
-                    }
+            if (f->smooth_symbols) {
+
+                for(i=0; i<bits_per_codec_frame; i++) {
+                    rx_bits[i] += rx_bits[i+bits_per_codec_frame];
+                    rx_bits[i+bits_per_codec_frame] = rx_bits[i];
                 }
+            }
 
-                for (j=0; j<COHPSK_BITS_PER_FRAME; j+=bits_per_codec_frame) {
+            byte = 0;
+            for (j=0; j<COHPSK_BITS_PER_FRAME; j+=bits_per_codec_frame) {
 
-                    /* extract txt msg data bit(s) */
+                /* extract txt msg data bit(s) */
 
-                    if (f->mode == FREEDV_MODE_700)
-                        nspare = 2;
-                    else
-                        nspare = 1;
+                if (f->mode == FREEDV_MODE_700)
+                    nspare = 2;
+                else
+                    nspare = 1;
 
-                    for(k=0; k<nspare; k++)  {
-                        abit[0] = rx_bits[data_flag_index+j+k] < 0.0;
+                for(k=0; k<nspare; 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);
-                        }
+                    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 */
+                /* 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++;
-                        }
+                bit = 7;
+                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++;
                     }
+                }
+               if (bit != 7)
+                   byte++;
 
-                    codec2_decode(f->codec2, speech_out, f->packed_codec_bits);
-
-                    if (f->squelch_en && (f->stats.snr_est < f->snr_squelch_thresh)) {
-                        for(i=0; i<f->n_speech_samples; i++)
-                            speech_out[i] = 0;
-                    }
-                    speech_out += codec2_samples_per_frame(f->codec2);
+                if (f->squelch_en && (f->stats.snr_est < f->snr_squelch_thresh)) {
+                  *valid = 0;
                 }
-                nout = f->n_speech_samples;
+               *valid = 1;
             }
-            else {
-                short error_pattern[COHPSK_BITS_PER_FRAME];
-                int   bit_errors;
+            nout = f->n_speech_samples;
+        }
+        else {
+            short error_pattern[COHPSK_BITS_PER_FRAME];
+            int   bit_errors;
 
-                /* test data, lets see if we can sync to the test data sequence */
+            /* test data, lets see if we can sync to the test data sequence */
 
-                cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors, rx_bits);
-                if (f->test_frame_sync_state) {
-                    f->total_bit_errors += bit_errors;
-                    f->total_bits       += COHPSK_BITS_PER_FRAME;
-                    if (f->freedv_put_error_pattern != NULL) {
-                        (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, COHPSK_BITS_PER_FRAME);
-                    }
+            cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors, rx_bits);
+            if (f->test_frame_sync_state) {
+                f->total_bit_errors += bit_errors;
+                f->total_bits       += COHPSK_BITS_PER_FRAME;
+                if (f->freedv_put_error_pattern != NULL) {
+                    (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, COHPSK_BITS_PER_FRAME);
                 }
-
-                for(i=0; i<f->n_speech_samples; i++)
-                    speech_out[i] = 0;
-                nout = f->n_speech_samples;
             }
-
+            
+           *valid = 0;
+            nout = f->n_speech_samples;
         }
 
+    }
 
-        /* no valid FreeDV signal - squelch output */
 
-        if (sync == 0) {
-            nout = freedv_nin(f);
-            if (f->squelch_en) {
-                for(i=0; i<nout; i++)
-                    speech_out[i] = 0;
-            }
+    /* no valid FreeDV signal - squelch output */
+
+    if (sync == 0) {
+        nout = freedv_nin(f);
+        if (f->squelch_en) {
+           *valid = 0;
         }
+    }
+    return nout;
+}
+#endif
+
+
+int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) {
+    assert(f != NULL);
+    int                 bits_per_codec_frame, bytes_per_codec_frame;
+    int                 i, nout = 0;
+    int valid;
+    
+    assert(f->nin <= f->n_max_modem_samples);
 
+    bits_per_codec_frame  = codec2_bits_per_frame(f->codec2);
+    bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
+
+    if (f->mode == FREEDV_MODE_1600) {
+        nout = freedv_comprx_fdmdv_1600(f, demod_in, &valid);
+    }
+#ifndef CORTEX_M4
+    if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B)) {
+        nout = freedv_comprx_fdmdv_700(f, demod_in, &valid);
     }
 #endif
 
+    if (valid == 0)
+        for (i = 0; i < nout; i++)
+            speech_out[i] = 0;
+    else if (valid < 0)
+        for (i = 0; i < nout; i++)
+           speech_out[i] = FDMDV_SCALE*demod_in[i].real;
+    else {
+       int frames = f->n_codec_bits / bits_per_codec_frame;
+       for (i = 0; i < frames; i++) {
+            codec2_decode(f->codec2, speech_out, f->packed_codec_bits + i * bytes_per_codec_frame);
+            speech_out += codec2_samples_per_frame(f->codec2);
+       }
+    }
+
     //fprintf(stderr,"freedv_nin(f): %d nout: %d\n", freedv_nin(f), nout);
     return nout;
 }
 
+int freedv_codecrx(struct freedv *f, unsigned char *packed_codec_bits, short demod_in[])
+{
+    assert(f != NULL);
+    COMP rx_fdm[f->n_max_modem_samples];
+    int i;
+    int nin = freedv_nin(f);
+    int valid;
+    int ret = 0;
+    float rx_float[f->n_max_modem_samples];
+
+    assert(nin <= f->n_max_modem_samples);
+
+    /* FSK RX happens in real floats, so convert to those and call their demod here */
+    if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ){
+        for(i=0; i<nin; i++) {
+            rx_float[i] = ((float)demod_in[i]);
+        }
+    } else {
+        for(i=0; i<nin; i++) {
+            rx_fdm[i].real = (float)demod_in[i];
+            rx_fdm[i].imag = 0.0;
+        }
+    }
+    
+    if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ){
+        freedv_floatrx_fsk_2400(f, rx_float, &valid);
+    }
+    if (f->mode == FREEDV_MODE_1600) {
+        freedv_comprx_fdmdv_1600(f, rx_fdm, &valid);
+    }
+#ifndef CORTEX_M4
+    if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B)) {
+        freedv_comprx_fdmdv_700(f, rx_fdm, &valid);
+    }
+#endif
+
+    if (valid == 0) {
+        int bytes_per_frame;
+        bytes_per_frame = (f->n_codec_bits + 7) / 8;
+
+        memcpy(packed_codec_bits, f->packed_codec_bits, bytes_per_frame);
+       ret = bytes_per_frame;
+    }
+    
+    return ret;
+}
+
 /*---------------------------------------------------------------------------*\
 
   FUNCTION....: freedv_get_version
@@ -1156,7 +1328,7 @@ int freedv_get_protocol_bits              (struct freedv *f) {return  f->n_proto
 int freedv_get_mode                       (struct freedv *f) {return f->mode;}
 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_modem_sample_rate          (struct freedv *f) {return FS;}
+int freedv_get_modem_sample_rate          (struct freedv *f) {return f->modem_sample_rate;}
 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;}
@@ -1166,6 +1338,7 @@ int freedv_get_sz_error_pattern           (struct freedv *f) {return  f->sz_erro
 // Get floats
 
 struct CODEC2 *freedv_get_codec2       (struct freedv *f){return  f->codec2;}
+int freedv_get_n_codec_bits             (struct freedv *f){return f->n_codec_bits;}
 
 void freedv_get_modem_extended_stats(struct freedv *f, struct MODEM_STATS *stats)
 {
index 80521a0879ba95a58eee94f364a3b22cf9304826..a9805781f0e1c932d50aa56bf0484eb2a3a4c203 100644 (file)
@@ -65,11 +65,13 @@ void freedv_close   (struct freedv *freedv);
 // 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[]);
+void freedv_codectx (struct freedv *f, short mod_out[], unsigned char *packed_codec_bits);
 // 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[]);
+int freedv_codecrx  (struct freedv *freedv, unsigned char *packed_codec_bits, short 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_callback_protocol       (struct freedv *freedv, freedv_callback_protorx rx, freedv_callback_prototx tx, void *callback_state);
@@ -97,6 +99,7 @@ int freedv_get_total_bits                     (struct freedv *freedv);
 int freedv_get_total_bit_errors                (struct freedv *freedv);
 int freedv_get_sync                        (struct freedv *freedv);
 struct CODEC2 *freedv_get_codec2       (struct freedv *freedv);
+int freedv_get_n_codec_bits             (struct freedv *freedv);
 int freedv_get_sz_error_pattern     (struct freedv *freedv);
 int freedv_get_protocol_bits        (struct freedv *freedv);
 #endif
index 0b5775297efbce747bd33dd573235ec5cd2b298f..0a0cfe315dc2cecc8bcf9110c7550d6d44116ac2 100644 (file)
@@ -89,6 +89,7 @@ struct freedv {
     int                  tx_sync_bit;
     int                  smooth_symbols;
     float               *prev_rx_bits;
+    int                  n_codec_bits;           // amount of codec bits in a frame
 
     int                 *ptest_bits_coh;
     int                 *ptest_bits_coh_end;