From 6cda1db8e69db8992d3698cb43b13f2335b0c10d Mon Sep 17 00:00:00 2001
From: "A. Maitland Bottoms" <bottoms@debian.org>
Date: Tue, 27 May 2014 15:07:22 -0700
Subject: vocoder: merge final codec2 update

---
 gr-vocoder/lib/codec2/c2dec.c           | 136 ++++++++++++++++++++++----------
 gr-vocoder/lib/codec2/c2demo.c          |   3 +-
 gr-vocoder/lib/codec2/c2enc.c           |  15 +++-
 gr-vocoder/lib/codec2/c2sim.c           |   8 +-
 gr-vocoder/lib/codec2/codec2.c          |  48 +++++++----
 gr-vocoder/lib/codec2/codec2.h          |   4 +-
 gr-vocoder/lib/codec2/codec2_internal.h |   1 +
 gr-vocoder/lib/codec2/dump.c            |  20 +++++
 gr-vocoder/lib/codec2/dump.h            |   1 +
 gr-vocoder/lib/codec2/nlp.c             |   2 +-
 gr-vocoder/lib/codec2/pack.c            |  49 ++++++++++--
 gr-vocoder/lib/codec2/quantise.h        |   2 +
 12 files changed, 217 insertions(+), 72 deletions(-)

(limited to 'gr-vocoder/lib/codec2')

diff --git a/gr-vocoder/lib/codec2/c2dec.c b/gr-vocoder/lib/codec2/c2dec.c
index df4e82f77a..ec44f0a9fd 100644
--- a/gr-vocoder/lib/codec2/c2dec.c
+++ b/gr-vocoder/lib/codec2/c2dec.c
@@ -26,18 +26,22 @@
 */
 
 #include "codec2.h"
+#include "dump.h"
 
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <getopt.h>
 
 #define NONE          0  /* no bit errors                          */
 #define UNIFORM       1  /* random bit errors                      */
 #define TWO_STATE     2  /* Two state error model                  */
 #define UNIFORM_RANGE 3  /* random bit errors over a certain range */
 
+void print_help(const struct option *long_options, int num_opts, char* argv[]);
+
 int main(int argc, char *argv[])
 {
     int            mode;
@@ -52,18 +56,25 @@ int main(int argc, char *argv[])
     int            state, next_state;
     float          ber, r, burst_length, burst_period, burst_timer, ber_est;
     unsigned char  mask;
-
-    if ((argc != 4) && (argc != 5) && (argc != 6) && (argc != 7)) {
-	printf("basic usage.................: c2dec 3200|2400|1600|1400|1300|1200 InputBitFile OutputRawSpeechFile\n");
-	printf("uniform errors usage........: c2dec 3200|2400|1600|1400|1300|1200 InputBitFile OutputRawSpeechFile uniformBER startBit endBit\n");
-	printf("uniform error on range usage: c2dec 3200|2400|1600|1400|1300|1200 InputBitFile OutputRawSpeechFile uniformBER\n");
-	printf("demod BER estimate..........: c2dec 3200|2400|1600|1400|1300|1200 InputBitFile OutputRawSpeechFile BERfile\n");
-	printf("two state fading usage......: c2dec 3200|2400|1600|1400|1300|1200 InputBitFile OutputRawSpeechFile burstLength burstPeriod\n");
-	printf("e.g    c2dec 1400 hts1a.c2 hts1a_1400.raw\n");
-	printf("e.g    c2dec 1400 hts1a.c2 hts1a_1400.raw 0.9\n");
-	printf("e.g    c2dec 1400 hts1a.c2 hts1a_1400.raw 0.99 0.9\n");
-	exit(1);
-    }
+    int            natural, dump;
+
+    char* opt_string = "h:";
+    struct option long_options[] = {
+        { "ber", required_argument, NULL, 0 },
+        { "startbit", required_argument, NULL, 0 },
+        { "endbit", required_argument, NULL, 0 },
+        { "berfile", required_argument, NULL, 0 },
+        { "natural", no_argument, &natural, 1 },
+        #ifdef DUMP
+        { "dump", required_argument, &dump, 1 },
+        #endif
+        { "help", no_argument, NULL, 'h' },
+        { NULL, no_argument, NULL, 0 }
+    };
+    int num_opts=sizeof(long_options)/sizeof(struct option);
+
+    if (argc < 4)
+        print_help(long_options, num_opts, argv);
 
     if (strcmp(argv[1],"3200") == 0)
 	mode = CODEC2_MODE_3200;
@@ -101,6 +112,7 @@ int main(int argc, char *argv[])
     ber = 0.0;
     burst_length = burst_period = 0.0;
     burst_timer = 0.0;
+    dump = natural = 0;
 
     codec2 = codec2_create(mode);
     nsam = codec2_samples_per_frame(codec2);
@@ -113,34 +125,50 @@ int main(int argc, char *argv[])
     nstart_bit = 0;
     nend_bit = nbit-1;
 
-    if (argc == 5) {
-        /* see if 4th argument is a valid file name */
-        if ( (fber = fopen(argv[4],"rb")) == NULL ) {
-            /* otherwise it must be BER value for uniform errors */
-            ber = atof(argv[4]);
-	    error_mode = UNIFORM;
-        }
-    }
+    while(1) {
+        int option_index = 0;
+        int opt = getopt_long(argc, argv, opt_string,
+                    long_options, &option_index);
+        if (opt == -1)
+            break;
+
+        switch (opt) {
+        case 0:
+            if(strcmp(long_options[option_index].name, "ber") == 0) {
+                ber = atof(optarg);
+                error_mode = UNIFORM;
+            } else if(strcmp(long_options[option_index].name, "startbit") == 0) {
+	        nstart_bit = atoi(optarg);
+            } else if(strcmp(long_options[option_index].name, "endbit") == 0) {
+	        nend_bit = atoi(optarg);
+             } else if(strcmp(long_options[option_index].name, "berfile") == 0) {
+	        if ((fber = fopen(optarg,"wt")) == NULL) {
+	            fprintf(stderr, "Error opening BER file: %s %s.\n",
+                            optarg, strerror(errno));
+                    exit(1);
+                }
 
-    if (argc == 6) {
-        error_mode = TWO_STATE;
-	burst_length = atof(argv[4]);
-	burst_period = atof(argv[5]);
-	nstart_bit = 0;
-	nend_bit = 2;
-        state = 0;
-    }
+            }
+            #ifdef DUMP
+            else if(strcmp(long_options[option_index].name, "dump") == 0) {
+                if (dump)
+	            dump_on(optarg);
+            }
+            #endif
+            break;
 
-    if (argc == 7) {
-        error_mode = UNIFORM_RANGE;
-	ber = atof(argv[4]);
-	nstart_bit = atoi(argv[5]);
-	nend_bit = atoi(argv[6]);
-        fprintf(stderr, "ber: %f nstart_bit: %d nend_bit: %d\n", ber, nstart_bit, nend_bit);
-        state = 0;
-    }
+        case 'h':
+            print_help(long_options, num_opts, argv);
+            break;
 
+        default:
+            /* This will never be reached */
+            break;
+        }
+    }
     assert(nend_bit <= nbit);
+    codec2_set_natural_or_gray(codec2, !natural);
+    //printf("%d %d\n", nstart_bit, nend_bit);
 
     while(fread(bits, sizeof(char), nbyte, fin) == (size_t)nbyte) {
 	frames++;
@@ -211,13 +239,7 @@ int main(int argc, char *argv[])
         else
             ber_est = 0.0;
 
-        /* frame repeat logic */
-        if (ber_est > 0.15) {
-            //memcpy(bits, prev_bits, nbyte);
-            // fprintf(stderr, "repeat\n");
-        }
-
-	codec2_decode(codec2, buf, bits, ber_est);
+	codec2_decode_ber(codec2, buf, bits, ber_est);
  	fwrite(buf, sizeof(short), nsam, fout);
 	//if this is in a pipeline, we probably don't want the usual
         //buffering to occur
@@ -239,3 +261,31 @@ int main(int argc, char *argv[])
 
     return 0;
 }
+
+void print_help(const struct option* long_options, int num_opts, char* argv[])
+{
+	int i;
+	char *option_parameters;
+	fprintf(stderr, "\nc2dec - Codec 2 decoder and bit error simulation program\n"
+		"usage: %s 3200|2400|1400}1300|1200 InputFile OutputRawFile [OPTIONS]\n\n"
+                "Options:\n", argv[0]);
+        for(i=0; i<num_opts-1; i++) {
+		if(long_options[i].has_arg == no_argument) {
+			option_parameters="";
+		} else if (strcmp("ber", long_options[i].name) == 0) {
+			option_parameters = " BER";
+		} else if (strcmp("startbit", long_options[i].name) == 0) {
+			option_parameters = " startBit";
+		} else if (strcmp("endbit", long_options[i].name) == 0) {
+			option_parameters = " endBit";
+		} else if (strcmp("berfile", long_options[i].name) == 0) {
+			option_parameters = " berFileName";
+		} else if (strcmp("dump", long_options[i].name) == 0) {
+			option_parameters = " dumpFilePrefix";
+		} else {
+			option_parameters = " <UNDOCUMENTED parameter>";
+		}
+		fprintf(stderr, "\t--%s%s\n", long_options[i].name, option_parameters);
+	}
+	exit(1);
+}
diff --git a/gr-vocoder/lib/codec2/c2demo.c b/gr-vocoder/lib/codec2/c2demo.c
index 0090069c65..9cd11d490e 100644
--- a/gr-vocoder/lib/codec2/c2demo.c
+++ b/gr-vocoder/lib/codec2/c2demo.c
@@ -33,6 +33,7 @@
 
 #include "codec2.h"
 #include "sine.h"
+#include "dump.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -85,7 +86,7 @@ int main(int argc, char *argv[])
 
     while(fread(buf, sizeof(short), nsam, fin) == (size_t)nsam) {
 	codec2_encode(codec2, bits, buf);
-	codec2_decode(codec2, buf, bits, 0.0);
+	codec2_decode(codec2, buf, bits);
 	fwrite(buf, sizeof(short), nsam, fout);
     }
 
diff --git a/gr-vocoder/lib/codec2/c2enc.c b/gr-vocoder/lib/codec2/c2enc.c
index ab1ebe4387..1e2760a01f 100644
--- a/gr-vocoder/lib/codec2/c2enc.c
+++ b/gr-vocoder/lib/codec2/c2enc.c
@@ -41,11 +41,12 @@ int main(int argc, char *argv[])
     FILE          *fout;
     short         *buf;
     unsigned char *bits;
-    int            nsam, nbit, nbyte;
+    int            nsam, nbit, nbyte, gray;
 
-    if (argc != 4) {
-	printf("usage: c2enc 3200|2400|1600|1400|1300|1200 InputRawspeechFile OutputBitFile\n");
+    if (argc < 4) {
+	printf("usage: c2enc 3200|2400|1600|1400|1300|1200 InputRawspeechFile OutputBitFile [--natural]\n");
 	printf("e.g    c2enc 1400 ../raw/hts1a.raw hts1a.c2\n");
+	printf("e.g    c2enc 1300 ../raw/hts1a.raw hts1a.c2 --natural\n");
 	exit(1);
     }
 
@@ -88,6 +89,14 @@ int main(int argc, char *argv[])
 
     bits = (unsigned char*)malloc(nbyte*sizeof(char));
 
+    if (argc == 5) {
+        if (strcmp(argv[4], "--natural") == 0)
+            gray = 0;
+        else
+            gray = 1;
+        codec2_set_natural_or_gray(codec2, gray);
+    }
+
     while(fread(buf, sizeof(short), nsam, fin) == (size_t)nsam) {
 	codec2_encode(codec2, bits, buf);
 	fwrite(bits, sizeof(char), nbyte, fout);
diff --git a/gr-vocoder/lib/codec2/c2sim.c b/gr-vocoder/lib/codec2/c2sim.c
index 8f07299d0d..e68f2aceeb 100644
--- a/gr-vocoder/lib/codec2/c2sim.c
+++ b/gr-vocoder/lib/codec2/c2sim.c
@@ -587,13 +587,19 @@ int main(int argc, char *argv[])
 			mel[i]++;
 		}
 
+                #ifdef DUMP
+                dump_mel(mel);
+                #endif
+
 		for(i=0; i<LPC_ORD; i++) {
 		    f_ = 700.0*( pow(10.0, (float)mel[i]/100.0) - 1.0);
 		    lsps_[i] = f_*(PI/4000.0);
 		}
-		for(i=5; i<10; i++) {
+                /*
+                for(i=5; i<10; i++) {
 		    lsps_[i] = lsps[i];
 		}
+                */
 
 		lsp_to_lpc(lsps_, ak, LPC_ORD);
 	    }
diff --git a/gr-vocoder/lib/codec2/codec2.c b/gr-vocoder/lib/codec2/codec2.c
index bc4a084839..5bf998064b 100644
--- a/gr-vocoder/lib/codec2/codec2.c
+++ b/gr-vocoder/lib/codec2/codec2.c
@@ -138,6 +138,8 @@ struct CODEC2 * CODEC2_WIN32SUPPORT codec2_create(int mode)
 	return NULL;
     }
 
+    c2->gray = 1;
+
     c2->lpc_pf = 1; c2->bass_boost = 1; c2->beta = LPCPF_BETA; c2->gamma = LPCPF_GAMMA;
 
     c2->xq_enc[0] = c2->xq_enc[1] = 0.0;
@@ -248,7 +250,12 @@ void CODEC2_WIN32SUPPORT codec2_encode(struct CODEC2 *c2, unsigned char *bits, s
 	codec2_encode_1200(c2, bits, speech);
 }
 
-void CODEC2_WIN32SUPPORT codec2_decode(struct CODEC2 *c2, short speech[], const unsigned char *bits, float ber_est)
+void CODEC2_WIN32SUPPORT codec2_decode(struct CODEC2 *c2, short speech[], const unsigned char *bits)
+{
+    codec2_decode_ber(c2, speech, bits, 0.0);
+}
+
+void CODEC2_WIN32SUPPORT codec2_decode_ber(struct CODEC2 *c2, short speech[], const unsigned char *bits, float ber_est)
 {
     assert(c2 != NULL);
     assert(
@@ -978,36 +985,36 @@ void codec2_encode_1300(struct CODEC2 *c2, unsigned char * bits, short speech[])
     /* frame 1: - voicing ---------------------------------------------*/
 
     analyse_one_frame(c2, &model, speech);
-    pack(bits, &nbit, model.voiced, 1);
+    pack_natural_or_gray(bits, &nbit, model.voiced, 1, c2->gray);
 
     /* frame 2: - voicing ---------------------------------------------*/
 
     analyse_one_frame(c2, &model, &speech[N]);
-    pack(bits, &nbit, model.voiced, 1);
+    pack_natural_or_gray(bits, &nbit, model.voiced, 1, c2->gray);
 
     /* frame 3: - voicing ---------------------------------------------*/
 
     analyse_one_frame(c2, &model, &speech[2*N]);
-    pack(bits, &nbit, model.voiced, 1);
+    pack_natural_or_gray(bits, &nbit, model.voiced, 1, c2->gray);
 
     /* frame 4: - voicing, scalar Wo & E, scalar LSPs ------------------*/
 
     analyse_one_frame(c2, &model, &speech[3*N]);
-    pack(bits, &nbit, model.voiced, 1);
+    pack_natural_or_gray(bits, &nbit, model.voiced, 1, c2->gray);
 
     Wo_index = encode_Wo(model.Wo);
-    pack(bits, &nbit, Wo_index, WO_BITS);
+    pack_natural_or_gray(bits, &nbit, Wo_index, WO_BITS, c2->gray);
 
     #ifdef TIMER
     quant_start = machdep_timer_sample();
     #endif
     e = speech_to_uq_lsps(lsps, ak, c2->Sn, c2->w, LPC_ORD);
     e_index = encode_energy(e);
-    pack(bits, &nbit, e_index, E_BITS);
+    pack_natural_or_gray(bits, &nbit, e_index, E_BITS, c2->gray);
 
     encode_lsps_scalar(lsp_indexes, lsps, LPC_ORD);
     for(i=0; i<LSP_SCALAR_INDEXES; i++) {
-	pack(bits, &nbit, lsp_indexes[i], lsp_bits(i));
+	pack_natural_or_gray(bits, &nbit, lsp_indexes[i], lsp_bits(i), c2->gray);
     }
     #ifdef TIMER
     machdep_timer_sample_and_log(quant_start, "    quant/packing");
@@ -1054,20 +1061,20 @@ void codec2_decode_1300(struct CODEC2 *c2, short speech[], const unsigned char *
     /* this will partially fill the model params for the 4 x 10ms
        frames */
 
-    model[0].voiced = unpack(bits, &nbit, 1);
-    model[1].voiced = unpack(bits, &nbit, 1);
-    model[2].voiced = unpack(bits, &nbit, 1);
-    model[3].voiced = unpack(bits, &nbit, 1);
+    model[0].voiced = unpack_natural_or_gray(bits, &nbit, 1, c2->gray);
+    model[1].voiced = unpack_natural_or_gray(bits, &nbit, 1, c2->gray);
+    model[2].voiced = unpack_natural_or_gray(bits, &nbit, 1, c2->gray);
+    model[3].voiced = unpack_natural_or_gray(bits, &nbit, 1, c2->gray);
 
-    Wo_index = unpack(bits, &nbit, WO_BITS);
+    Wo_index = unpack_natural_or_gray(bits, &nbit, WO_BITS, c2->gray);
     model[3].Wo = decode_Wo(Wo_index);
     model[3].L  = PI/model[3].Wo;
 
-    e_index = unpack(bits, &nbit, E_BITS);
+    e_index = unpack_natural_or_gray(bits, &nbit, E_BITS, c2->gray);
     e[3] = decode_energy(e_index);
 
     for(i=0; i<LSP_SCALAR_INDEXES; i++) {
-	lsp_indexes[i] = unpack(bits, &nbit, lsp_bits(i));
+	lsp_indexes[i] = unpack_natural_or_gray(bits, &nbit, lsp_bits(i), c2->gray);
     }
     decode_lsps_scalar(&lsps[3][0], lsp_indexes, LPC_ORD);
     check_lsp_order(&lsps[3][0], LPC_ORD);
@@ -1101,6 +1108,10 @@ void codec2_decode_1300(struct CODEC2 *c2, short speech[], const unsigned char *
 	apply_lpc_correction(&model[i]);
     }
     TIMER_SAMPLE_AND_LOG2(recover_start, "    recover");
+    #ifdef DUMP
+    dump_lsp_(&lsps[3][0]);
+    dump_ak_(&ak[3][0], LPC_ORD);
+    #endif
 
     /* synthesise ------------------------------------------------*/
 
@@ -1519,3 +1530,10 @@ int CODEC2_WIN32SUPPORT codec2_rebuild_spare_bit(struct CODEC2 *c2, int unpacked
 
     return -1;
 }
+
+void CODEC2_WIN32SUPPORT codec2_set_natural_or_gray(struct CODEC2 *c2, int gray)
+{
+    assert(c2 != NULL);
+    c2->gray = gray;
+}
+
diff --git a/gr-vocoder/lib/codec2/codec2.h b/gr-vocoder/lib/codec2/codec2.h
index 2f0c2b1246..1e870db4f5 100644
--- a/gr-vocoder/lib/codec2/codec2.h
+++ b/gr-vocoder/lib/codec2/codec2.h
@@ -58,13 +58,15 @@ struct CODEC2;
 struct CODEC2 * CODEC2_WIN32SUPPORT codec2_create(int mode);
 void CODEC2_WIN32SUPPORT codec2_destroy(struct CODEC2 *codec2_state);
 void CODEC2_WIN32SUPPORT codec2_encode(struct CODEC2 *codec2_state, unsigned char * bits, short speech_in[]);
-      void CODEC2_WIN32SUPPORT codec2_decode(struct CODEC2 *codec2_state, short speech_out[], const unsigned char *bits, float ber_est);
+void CODEC2_WIN32SUPPORT codec2_decode(struct CODEC2 *codec2_state, short speech_out[], const unsigned char *bits);
+void CODEC2_WIN32SUPPORT codec2_decode_ber(struct CODEC2 *codec2_state, short speech_out[], const unsigned char *bits, float ber_est);
 int  CODEC2_WIN32SUPPORT codec2_samples_per_frame(struct CODEC2 *codec2_state);
 int  CODEC2_WIN32SUPPORT codec2_bits_per_frame(struct CODEC2 *codec2_state);
 
 void CODEC2_WIN32SUPPORT codec2_set_lpc_post_filter(struct CODEC2 *codec2_state, int enable, int bass_boost, float beta, float gamma);
 int  CODEC2_WIN32SUPPORT codec2_get_spare_bit_index(struct CODEC2 *codec2_state);
 int  CODEC2_WIN32SUPPORT codec2_rebuild_spare_bit(struct CODEC2 *codec2_state, int unpacked_bits[]);
+void CODEC2_WIN32SUPPORT codec2_set_natural_or_gray(struct CODEC2 *codec2_state, int gray);
 
 #endif
 
diff --git a/gr-vocoder/lib/codec2/codec2_internal.h b/gr-vocoder/lib/codec2/codec2_internal.h
index 246d1ae6af..c4bb1fc42a 100644
--- a/gr-vocoder/lib/codec2/codec2_internal.h
+++ b/gr-vocoder/lib/codec2/codec2_internal.h
@@ -38,6 +38,7 @@ struct CODEC2 {
     float         Sn[M];                   /* input speech                              */
     float         hpf_states[2];           /* high pass filter states                   */
     void         *nlp;                     /* pitch predictor states                    */
+    int           gray;                    /* non-zero for gray encoding                */
 
     kiss_fft_cfg  fft_inv_cfg;             /* inverse FFT config                        */
     float         Sn_[2*N];	           /* synthesised output speech                 */
diff --git a/gr-vocoder/lib/codec2/dump.c b/gr-vocoder/lib/codec2/dump.c
index cc935d73cf..af966e5005 100644
--- a/gr-vocoder/lib/codec2/dump.c
+++ b/gr-vocoder/lib/codec2/dump.c
@@ -54,6 +54,7 @@ static FILE *frw = NULL;
 static FILE *flsp = NULL;
 static FILE *fweights = NULL;
 static FILE *flsp_ = NULL;
+static FILE *fmel = NULL;
 static FILE *fphase = NULL;
 static FILE *fphase_ = NULL;
 static FILE *ffw = NULL;
@@ -101,6 +102,8 @@ void dump_off(){
 	fclose(fweights);
     if (flsp_ != NULL)
 	fclose(flsp_);
+    if (fmel != NULL)
+	fclose(fmel);
     if (fphase != NULL)
 	fclose(fphase);
     if (fphase_ != NULL)
@@ -453,6 +456,23 @@ void dump_lsp_(float lsp_[]) {
     fprintf(flsp_,"\n");
 }
 
+void dump_mel(int mel[]) {
+    int i;
+    char s[MAX_STR];
+
+    if (!dumpon) return;
+
+    if (fmel == NULL) {
+	sprintf(s,"%s_mel.txt", prefix);
+	fmel = fopen(s, "wt");
+	assert(fmel != NULL);
+    }
+
+    for(i=0; i<10; i++)
+	fprintf(fmel,"%d\t",mel[i]);
+    fprintf(fmel,"\n");
+}
+
 void dump_ak(float ak[], int order) {
     int i;
     char s[MAX_STR];
diff --git a/gr-vocoder/lib/codec2/dump.h b/gr-vocoder/lib/codec2/dump.h
index a61fdaab69..dd95f5adad 100644
--- a/gr-vocoder/lib/codec2/dump.h
+++ b/gr-vocoder/lib/codec2/dump.h
@@ -49,6 +49,7 @@ void dump_Rw(float Rw[]);
 void dump_lsp(float lsp[]);
 void dump_weights(float w[], int ndim);
 void dump_lsp_(float lsp_[]);
+void dump_mel(int mel[]);
 void dump_ak(float ak[], int order);
 void dump_ak_(float ak[], int order);
 void dump_E(float E);
diff --git a/gr-vocoder/lib/codec2/nlp.c b/gr-vocoder/lib/codec2/nlp.c
index cca835b46f..83375dcd78 100644
--- a/gr-vocoder/lib/codec2/nlp.c
+++ b/gr-vocoder/lib/codec2/nlp.c
@@ -53,7 +53,7 @@
 #define CNLP        0.3	        /* post processor constant              */
 #define NLP_NTAP 48	        /* Decimation LPF order */
 
-#undef DUMP
+//#undef DUMP
 
 /*---------------------------------------------------------------------------*\
 
diff --git a/gr-vocoder/lib/codec2/pack.c b/gr-vocoder/lib/codec2/pack.c
index 3f8f93e422..1c07230a70 100644
--- a/gr-vocoder/lib/codec2/pack.c
+++ b/gr-vocoder/lib/codec2/pack.c
@@ -52,8 +52,22 @@ pack(
  unsigned int		fieldWidth/* Width of the field in BITS, not bytes. */
  )
 {
-  /* Convert the field to Gray code */
-  field = (field >> 1) ^ field;
+    pack_natural_or_gray(bitArray, bitIndex, field, fieldWidth, 1);
+}
+
+void
+pack_natural_or_gray(
+ unsigned char *	bitArray,  /* The output bit string. */
+ unsigned int *		bitIndex,  /* Index into the string in BITS, not bytes.*/
+ int			field,	   /* The bit field to be packed. */
+ unsigned int		fieldWidth,/* Width of the field in BITS, not bytes. */
+ unsigned int           gray       /* non-zero for gray coding */
+ )
+{
+  if (gray) {
+    /* Convert the field to Gray code */
+    field = (field >> 1) ^ field;
+  }
 
   do {
     unsigned int  	bI = *bitIndex;
@@ -80,6 +94,21 @@ unpack(
  unsigned int *		bitIndex, /* Index into the string in BITS, not bytes.*/
  unsigned int		fieldWidth/* Width of the field in BITS, not bytes. */
  )
+{
+    return unpack_natural_or_gray(bitArray, bitIndex, fieldWidth, 1);
+}
+
+/** Unpack a field from a bit string, to binary, optionally using
+ * natural or Gray code.
+ *
+ */
+int
+unpack_natural_or_gray(
+ const unsigned char *	bitArray,  /* The input bit string. */
+ unsigned int *		bitIndex,  /* Index into the string in BITS, not bytes.*/
+ unsigned int		fieldWidth,/* Width of the field in BITS, not bytes. */
+ unsigned int           gray       /* non-zero for Gray coding */
+ )
 {
   unsigned int	field = 0;
   unsigned int	t;
@@ -96,10 +125,16 @@ unpack(
     fieldWidth -= sliceWidth;
   } while ( fieldWidth != 0 );
 
-  /* Convert from Gray code to binary. Works for maximum 8-bit fields. */
-  t = field ^ (field >> 8);
-  t ^= (t >> 4);
-  t ^= (t >> 2);
-  t ^= (t >> 1);
+  if (gray) {
+    /* Convert from Gray code to binary. Works for maximum 8-bit fields. */
+    t = field ^ (field >> 8);
+    t ^= (t >> 4);
+    t ^= (t >> 2);
+    t ^= (t >> 1);
+  }
+  else {
+    t = field;
+  }
+
   return t;
 }
diff --git a/gr-vocoder/lib/codec2/quantise.h b/gr-vocoder/lib/codec2/quantise.h
index 0932d9d1bd..cb9dd07fdb 100644
--- a/gr-vocoder/lib/codec2/quantise.h
+++ b/gr-vocoder/lib/codec2/quantise.h
@@ -96,7 +96,9 @@ int encode_energy(float e);
 float decode_energy(int index);
 
 void pack(unsigned char * bits, unsigned int *nbit, int index, unsigned int index_bits);
+void pack_natural_or_gray(unsigned char * bits, unsigned int *nbit, int index, unsigned int index_bits, unsigned int gray);
 int  unpack(const unsigned char * bits, unsigned int *nbit, unsigned int index_bits);
+int  unpack_natural_or_gray(const unsigned char * bits, unsigned int *nbit, unsigned int index_bits, unsigned int gray);
 
 int lsp_bits(int i);
 int lspd_bits(int i);
-- 
cgit v1.2.3