integrated freedv 700 mode into the freedv API
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sat, 13 Jun 2015 00:18:57 +0000 (00:18 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sat, 13 Jun 2015 00:18:57 +0000 (00:18 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@2182 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/src/codec2.c
codec2-dev/src/codec2_cohpsk.h
codec2-dev/src/cohpsk.c
codec2-dev/src/cohpsk_ch.c
codec2-dev/src/cohpsk_demod.c
codec2-dev/src/cohpsk_mod.c
codec2-dev/src/freedv_api.c
codec2-dev/src/freedv_api.h
codec2-dev/src/freedv_rx.c
codec2-dev/src/freedv_tx.c

index d12086416d9c3ca57873b499d734a950c3d453c3..debb89eb54e901e1e3f01226a4a7a54ec21ffa61 100644 (file)
@@ -1690,6 +1690,9 @@ int codec2_get_spare_bit_index(struct CODEC2 *c2)
     case CODEC2_MODE_1600:
         return 15; // bit 15 (16th bit) is v2 (third voicing bit)
         break;
+    case CODEC2_MODE_700:
+        return 26; // bits 26 and 27 are spare
+        break;
     }
     
     return -1;
index 9dce5806f00fd22492e89ae295d8088c8822c991..273a2c912bbbea987ab486c7b4b522b7420f1371 100644 (file)
 #ifndef __CODEC2_COHPSK__
 #define __CODEC2_COHPSK__
 
-#define COHPSK_BITS_PER_FRAME     56              /* hard coded for now */
-#define COHPSK_NC                  7              /* hard coded for now */
-#define COHPSK_SAMPLES_PER_FRAME 600
-#define COHPSK_RS                 75
-#define COHPSK_FS               7500              /* note this is a wierd value to get an integer oversampling rate */
+#define COHPSK_BITS_PER_FRAME         56              /* hard coded for now */
+#define COHPSK_NC                      7              /* hard coded for now */
+#define COHPSK_NOM_SAMPLES_PER_FRAME 600
+#define COHPSK_MAX_SAMPLES_PER_FRAME 625
+#define COHPSK_RS                     75
+#define COHPSK_FS                   7500              /* note this is a wierd 
+                                                         value to get an integer 
+                                                         oversampling rate */
 
 #include "comp.h"
 
index a87203ea60aedf2393685ede1379cdd23f0a63e2..677d4f7293f9d7d5085df64f85f588908ad5cd1d 100644 (file)
@@ -86,7 +86,8 @@ struct COHPSK *cohpsk_create(void)
     float          freq_hz;
 
     assert(COHPSK_NC == PILOTS_NC);
-    assert(COHPSK_SAMPLES_PER_FRAME == COHPSK_M*NSYMROWPILOT);
+    assert(COHPSK_NOM_SAMPLES_PER_FRAME == (COHPSK_M*NSYMROWPILOT));
+    assert(COHPSK_MAX_SAMPLES_PER_FRAME == (COHPSK_M*NSYMROWPILOT+COHPSK_M/P));
     assert(COHPSK_ND == ND);
     assert(COHPSK_NSYM == NSYM);  /* as we want to use the tx sym mem on fdmdv */
     assert(COHPSK_NT == NT);
@@ -619,7 +620,7 @@ int sync_state_machine(struct COHPSK *coh, int sync, int next_sync)
   DATE CREATED: 5/4/2015
 
   COHPSK modulator, take a frame of COHPSK_BITS_PER_FRAME bits and
-  generates a frame of COHPSK_SAMPLES_PER_FRAME modulated symbols.
+  generates a frame of COHPSK_NOM_SAMPLES_PER_FRAME modulated symbols.
 
   The output signal is complex to support single sided frequency
   shifting, for example when testing frequency offsets in channel
@@ -662,7 +663,7 @@ void cohpsk_clip(COMP tx_fdm[])
     float mag;
     int   i;
 
-    for(i=0; i<COHPSK_SAMPLES_PER_FRAME; i++) {
+    for(i=0; i<COHPSK_NOM_SAMPLES_PER_FRAME; i++) {
         sam = tx_fdm[i];
         mag = cabsolute(sam);            
         if (mag >  COHPSK_CLIP)  {
@@ -907,7 +908,7 @@ void rate_Fs_rx_processing(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC*ND], COM
   DATE CREATED: 5/4/2015
 
   COHPSK demodulator, takes an array of (nominally) nin_frame =
-  COHPSK_SAMPLES_PER_FRAME modulated samples, returns an array of
+  COHPSK_NOM_SAMPLES_PER_FRAME modulated samples, returns an array of
   COHPSK_BITS_PER_FRAME bits.
 
   The input signal is complex to support single sided frequency shifting
@@ -921,6 +922,8 @@ void cohpsk_demod(struct COHPSK *coh, float rx_bits[], int *reliable_sync_bit, C
     int   i, j, sync, anext_sync, next_sync, nin, r, c;
     float max_ratio, f_est;
 
+    assert(*nin_frame <= COHPSK_MAX_SAMPLES_PER_FRAME);
+
     next_sync = sync = coh->sync;
 
     for (i=0; i<NSW*NSYMROWPILOT*COHPSK_M-*nin_frame; i++)
index 6258c2851ca423f51e0a3ca5a35a5e30d1985579..6aa96b946a67f3136a4f9c1145fed44ff03694bb 100644 (file)
@@ -148,9 +148,9 @@ int main(int argc, char *argv[])
             nhfdelay = floor(SLOW_FADING_DELAY_MS*COHPSK_FS/1000);
         }
 
-        ch_fdm_delay = (COMP*)malloc((nhfdelay+COHPSK_SAMPLES_PER_FRAME)*sizeof(COMP));
+        ch_fdm_delay = (COMP*)malloc((nhfdelay+COHPSK_NOM_SAMPLES_PER_FRAME)*sizeof(COMP));
         assert(ch_fdm_delay != NULL);
-        for(i=0; i<nhfdelay+COHPSK_SAMPLES_PER_FRAME; i++) {
+        for(i=0; i<nhfdelay+COHPSK_NOM_SAMPLES_PER_FRAME; i++) {
             ch_fdm_delay[i].real = 0.0;
             ch_fdm_delay[i].imag = 0.0;
         }
index a3ea89f56705a9ac708e9949140a304109c6ff7a..c5375d56c370be2b190a06498bfba9fb119b3eb8 100644 (file)
@@ -47,8 +47,8 @@ int main(int argc, char *argv[])
     FILE          *fin, *fout, *foct;
     struct COHPSK *cohpsk;
     float         rx_bits[COHPSK_BITS_PER_FRAME];
-    COMP          rx_fdm[COHPSK_SAMPLES_PER_FRAME];
-    short         rx_fdm_scaled[COHPSK_SAMPLES_PER_FRAME];
+    COMP          rx_fdm[COHPSK_MAX_SAMPLES_PER_FRAME];
+    short         rx_fdm_scaled[COHPSK_MAX_SAMPLES_PER_FRAME];
     int           frames, reliable_sync_bit, nin_frame;
     float        *rx_amp_log;
     float        *rx_phi_log;
@@ -103,7 +103,7 @@ int main(int argc, char *argv[])
     log_data_r = 0;
     frames = 0;
 
-    nin_frame = COHPSK_SAMPLES_PER_FRAME;
+    nin_frame = COHPSK_NOM_SAMPLES_PER_FRAME;
     while(fread(rx_fdm_scaled, sizeof(short), nin_frame, fin) == nin_frame) {
        frames++;
 
index 5220f8263f4bc50e782c562b755da705497ea874..c47f0de50a05a176412f916f42f98d2f6d64de2d 100644 (file)
@@ -43,8 +43,8 @@ int main(int argc, char *argv[])
     struct COHPSK *cohpsk;
     float         tx_bits_sd[COHPSK_BITS_PER_FRAME];
     int           tx_bits[COHPSK_BITS_PER_FRAME];
-    COMP          tx_fdm[COHPSK_SAMPLES_PER_FRAME];
-    short         tx_fdm_scaled[COHPSK_SAMPLES_PER_FRAME];
+    COMP          tx_fdm[COHPSK_NOM_SAMPLES_PER_FRAME];
+    short         tx_fdm_scaled[COHPSK_NOM_SAMPLES_PER_FRAME];
     int           frames;
     int           i;
 
@@ -81,10 +81,10 @@ int main(int argc, char *argv[])
 
        /* scale and save to disk as shorts */
 
-       for(i=0; i<COHPSK_SAMPLES_PER_FRAME; i++)
+       for(i=0; i<COHPSK_NOM_SAMPLES_PER_FRAME; i++)
            tx_fdm_scaled[i] = FDMDV_SCALE * tx_fdm[i].real;
 
-       fwrite(tx_fdm_scaled, sizeof(short), COHPSK_SAMPLES_PER_FRAME, fout);
+       fwrite(tx_fdm_scaled, sizeof(short), COHPSK_NOM_SAMPLES_PER_FRAME, fout);
 
        /* if this is in a pipeline, we probably don't want the usual
           buffering to occur */
index 1a21fb832118ed1fac45b1da3cab8064b6ce5857..53de89c67536d8bcf4a19c396bf3ca161a4ce7f6 100644 (file)
 #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"
 
 /*---------------------------------------------------------------------------*\
                                                        
@@ -57,44 +60,70 @@ struct freedv *freedv_open(int mode) {
     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);
@@ -103,11 +132,8 @@ struct freedv *freedv_open(int mode) {
     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;
 }
 
@@ -122,10 +148,15 @@ struct freedv *freedv_open(int mode) {
 \*---------------------------------------------------------------------------*/
 
 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);
 }
@@ -139,66 +170,90 @@ void freedv_close(struct freedv *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]
@@ -228,23 +283,75 @@ void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]) {
             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) {
@@ -273,9 +380,12 @@ 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
@@ -284,27 +394,34 @@ int freedv_nin(struct freedv *f) {
 
 \*---------------------------------------------------------------------------*/
 
+
 // 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;
@@ -316,106 +433,167 @@ 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);
     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;
 }
index 1dbe867781f99acd9b6156a55d4d317f0b224673..1382dcfc7e13db67cc79de30a0320dff00a98b41 100644 (file)
 
 #define FREEDV_MODE_1600        0
 #define FREEDV_MODE_700         1
-#define FREEDV_NSAMPLES       320
 
 #include "varicode.h"
 #include "codec2_fdmdv.h"
+#include "codec2_cohpsk.h"
 
 struct freedv {
     int                  mode;
@@ -47,6 +47,14 @@ struct freedv {
     struct CODEC2       *codec2;
     struct FDMDV        *fdmdv;
     struct FDMDV_STATS   fdmdv_stats;
+    struct COHPSK       *cohpsk;
+
+    int                  n_speech_samples;
+    int                  n_nom_modem_samples;    // size of tx and most rx modenm sample buffers
+    int                  n_max_modem_samples;    // make your rx modem sample buffers this big
+
+    int                  modem_sample_rate;      // caller is responsible for meeting this
+    int                  clip;                   // non-zero for cohpsk modem output clipping for low PAPR
 
     unsigned char       *packed_codec_bits;
     int                 *codec_bits;
@@ -76,7 +84,10 @@ struct freedv {
 
 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[]);
index 94744a96528b4a50a660590a11aa88e932142c45..740a33e8feaa3d7fea83b0e7b0ce47588e24a57a 100644 (file)
@@ -42,50 +42,63 @@ struct my_callback_state {
 void my_put_next_rx_char(void *callback_state, char c) {
     struct my_callback_state* pstate = (struct my_callback_state*)callback_state;
     if (pstate->ftxt != NULL) {
-        fprintf(pstate->ftxt, "text char received callback: %c\n", c);
+        fprintf(stderr, "%c", c);
     }
 }
 
 int main(int argc, char *argv[]) {
     FILE                      *fin, *fout, *ftxt;
-    short                      speech_out[FREEDV_NSAMPLES];
-    short                      demod_in[FREEDV_NSAMPLES];
+    short                     *speech_out;
+    short                     *demod_in;
     struct freedv             *freedv;
     int                        nin, nout, frame;
     struct my_callback_state   my_cb_state;
+    int                        mode;
 
-    if (argc < 3) {
-       printf("usage: %s InputModemSpeechFile OutputSpeechawFile txtLogFile\n", argv[0]);
-       printf("e.g    %s hts1a_fdmdv.raw hts1a_out.raw txtLogFile\n", argv[0]);
+    if (argc < 4) {
+       printf("usage: %s 1600|700 InputModemSpeechFile OutputSpeechawFile txtLogFile\n", argv[0]);
+       printf("e.g    %s 1600 hts1a_fdmdv.raw hts1a_out.raw txtLogFile\n", argv[0]);
        exit(1);
     }
 
-    if (strcmp(argv[1], "-")  == 0) fin = stdin;
-    else if ( (fin = fopen(argv[1],"rb")) == NULL ) {
+    mode = -1;
+    if (!strcmp(argv[1],"1600"))
+        mode = FREEDV_MODE_1600;
+    if (!strcmp(argv[1],"700"))
+        mode = FREEDV_MODE_700;
+    assert(mode != -1);
+
+    if (strcmp(argv[2], "-")  == 0) fin = stdin;
+    else if ( (fin = fopen(argv[2],"rb")) == NULL ) {
        fprintf(stderr, "Error opening input raw modem sample file: %s: %s.\n",
-         argv[1], strerror(errno));
+         argv[2], strerror(errno));
        exit(1);
     }
 
-    if (strcmp(argv[2], "-") == 0) fout = stdout;
-    else if ( (fout = fopen(argv[2],"wb")) == NULL ) {
+    if (strcmp(argv[3], "-") == 0) fout = stdout;
+    else if ( (fout = fopen(argv[3],"wb")) == NULL ) {
        fprintf(stderr, "Error opening output speech sample file: %s: %s.\n",
-         argv[2], strerror(errno));
+         argv[3], strerror(errno));
        exit(1);
     }
     
     ftxt = NULL;
-    if ( (argc > 3) && (strcmp(argv[3],"|") != 0) ) {
-        if ((ftxt = fopen(argv[3],"wt")) == NULL ) {
+    if ( (argc > 4) && (strcmp(argv[4],"|") != 0) ) {
+        if ((ftxt = fopen(argv[4],"wt")) == NULL ) {
             fprintf(stderr, "Error opening txt Log File: %s: %s.\n",
-                    argv[3], strerror(errno));
+                    argv[4], strerror(errno));
             exit(1);
         }
     }
     
-    freedv = freedv_open(FREEDV_MODE_1600);
+    freedv = freedv_open(mode);
     assert(freedv != NULL);
 
+    speech_out = (short*)malloc(sizeof(short)*freedv->n_speech_samples);
+    assert(speech_out != NULL);
+    demod_in = (short*)malloc(sizeof(short)*freedv->n_max_modem_samples);
+    assert(demod_in != NULL);
+
     my_cb_state.ftxt = ftxt;
     freedv->callback_state = (void*)&my_cb_state;
     freedv->freedv_put_next_rx_char = &my_put_next_rx_char;
@@ -118,6 +131,8 @@ int main(int argc, char *argv[]) {
         if (fin == stdin) fflush(stdin);         
     }
 
+    free(speech_out);
+    free(demod_in);
     freedv_close(freedv);
     fclose(fin);
     fclose(fout);
index ac0cdca840102e6330d597d455159881570dd90b..c13303c727eebc7e7f83fcce502bb27e468cbd8f 100644 (file)
@@ -51,34 +51,47 @@ char my_get_next_tx_char(void *callback_state) {
 
 int main(int argc, char *argv[]) {
     FILE                     *fin, *fout;
-    short                     speech_in[FREEDV_NSAMPLES];
-    short                     mod_out[FREEDV_NSAMPLES];
+    short                    *speech_in;
+    short                    *mod_out;
     struct freedv            *freedv;
     struct my_callback_state  my_cb_state;
+    int                       mode;
 
-    if (argc < 3) {
-       printf("usage: %s InputRawSpeechFile OutputModemRawFile\n", argv[0]);
-       printf("e.g    %s hts1a.raw hts1a_fdmdv.raw\n", argv[0]);
+    if (argc < 4) {
+       printf("usage: %s 1600|700 InputRawSpeechFile OutputModemRawFile\n", argv[0]);
+       printf("e.g    %s 1600 hts1a.raw hts1a_fdmdv.raw\n", argv[0]);
        exit(1);
     }
 
-    if (strcmp(argv[1], "-")  == 0) fin = stdin;
-    else if ( (fin = fopen(argv[1],"rb")) == NULL ) {
+    mode = -1;
+    if (!strcmp(argv[1],"1600"))
+        mode = FREEDV_MODE_1600;
+    if (!strcmp(argv[1],"700"))
+        mode = FREEDV_MODE_700;
+    assert(mode != -1);
+
+    if (strcmp(argv[2], "-")  == 0) fin = stdin;
+    else if ( (fin = fopen(argv[2],"rb")) == NULL ) {
        fprintf(stderr, "Error opening input raw speech sample file: %s: %s.\n",
-         argv[1], strerror(errno));
+         argv[2], strerror(errno));
        exit(1);
     }
 
-    if (strcmp(argv[2], "-") == 0) fout = stdout;
-    else if ( (fout = fopen(argv[2],"wb")) == NULL ) {
+    if (strcmp(argv[3], "-") == 0) fout = stdout;
+    else if ( (fout = fopen(argv[3],"wb")) == NULL ) {
        fprintf(stderr, "Error opening output modem sample file: %s: %s.\n",
-         argv[2], strerror(errno));
+         argv[3], strerror(errno));
        exit(1);
     }
     
-    freedv = freedv_open(FREEDV_MODE_1600);
+    freedv = freedv_open(mode);
     assert(freedv != NULL);
 
+    speech_in = (short*)malloc(sizeof(short)*freedv->n_speech_samples);
+    assert(speech_in != NULL);
+    mod_out = (short*)malloc(sizeof(short)*freedv->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");
@@ -88,9 +101,9 @@ int main(int argc, char *argv[]) {
 
     /* OK main loop */
 
-    while(fread(speech_in, sizeof(short), FREEDV_NSAMPLES, fin) == FREEDV_NSAMPLES) {
+    while(fread(speech_in, sizeof(short), freedv->n_speech_samples, fin) == freedv->n_speech_samples) {
         freedv_tx(freedv, mod_out, speech_in);
-        fwrite(mod_out, sizeof(short), FREEDV_NSAMPLES, fout);
+        fwrite(mod_out, sizeof(short), freedv->n_nom_modem_samples, fout);
 
        /* if this is in a pipeline, we probably don't want the usual
            buffering to occur */
@@ -99,6 +112,8 @@ int main(int argc, char *argv[]) {
         if (fin == stdin) fflush(stdin);         
     }
 
+    free(speech_in);
+    free(mod_out);
     freedv_close(freedv);
     fclose(fin);
     fclose(fout);