1 /*---------------------------------------------------------------------------*\
2 
3   FILE........: c2dec.c
4   AUTHOR......: David Rowe
5   DATE CREATED: 23/8/2010
6 
7   Decodes a file of bits to a file of raw speech samples using codec2.
8 
9 \*---------------------------------------------------------------------------*/
10 
11 /*
12   Copyright (C) 2010 David Rowe
13 
14   All rights reserved.
15 
16   This program is free software; you can redistribute it and/or modify
17   it under the terms of the GNU Lesser General Public License version 2.1, as
18   published by the Free Software Foundation.  This program is
19   distributed in the hope that it will be useful, but WITHOUT ANY
20   WARRANTY; without even the implied warranty of MERCHANTABILITY or
21   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
22   License for more details.
23 
24   You should have received a copy of the GNU Lesser General Public License
25   along with this program; if not, see <http://www.gnu.org/licenses/>.
26 */
27 
28 #include "codec2.h"
29 #include "dump.h"
30 #include "c2file.h"
31 
32 #include <assert.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <getopt.h>
38 
39 #define NONE          0  /* no bit errors                          */
40 #define UNIFORM       1  /* random bit errors                      */
41 #define TWO_STATE     2  /* Two state error model                  */
42 #define UNIFORM_RANGE 3  /* random bit errors over a certain range */
43 
44 void print_help(const struct option *long_options, int num_opts, char* argv[]);
45 
main(int argc,char * argv[])46 int main(int argc, char *argv[])
47 {
48     int            mode=0;
49     void          *codec2;
50     FILE          *fin;
51     FILE          *fout;
52     FILE          *fber = NULL;
53     short         *buf;
54     unsigned char *bits;
55     float         *softdec_bits;
56     char          *bitperchar_bits;
57     int            nsam, nbit, nbyte, i, byte, frames, bits_proc, bit_errors, error_mode;
58     int            nstart_bit, nend_bit, bit_rate;
59     int            state, next_state;
60     float          ber, r, burst_length, burst_period, burst_timer, ber_est;
61     unsigned char  mask;
62     int            natural, softdec, bit, ret, bitperchar;
63 #ifdef DUMP
64     int dump;
65 #endif
66     int            report_energy;
67     FILE          *f_ratek = NULL;
68     float         *user_ratek;
69     int            K;
70 
71     char* opt_string = "h:";
72     struct option long_options[] = {
73         { "ber", required_argument, NULL, 0 },
74         { "startbit", required_argument, NULL, 0 },
75         { "endbit", required_argument, NULL, 0 },
76         { "berfile", required_argument, NULL, 0 },
77         { "natural", no_argument, &natural, 1 },
78         { "softdec", no_argument, &softdec, 1 },
79         { "bitperchar", no_argument, &bitperchar, 1 },
80         #ifdef DUMP
81         { "dump", required_argument, &dump, 1 },
82         #endif
83 	{ "energy", no_argument, NULL, 0 },
84         { "mlfeat", required_argument, NULL, 0 },
85         { "loadcb", required_argument, NULL, 0 },
86         { "loadratek", required_argument, NULL, 0 },
87         { "nopf", no_argument, NULL, 0 },
88         { "help", no_argument, NULL, 'h' },
89         { NULL, no_argument, NULL, 0 }
90     };
91     int num_opts=sizeof(long_options)/sizeof(struct option);
92 
93     if (argc < 4)
94         print_help(long_options, num_opts, argv);
95 
96     if (strcmp(argv[2], "-")  == 0) fin = stdin;
97     else if ( (fin = fopen(argv[2],"rb")) == NULL ) {
98 	fprintf(stderr, "Error opening input bit file: %s: %s.\n",
99          argv[2], strerror(errno));
100 	exit(1);
101     }
102 
103     if (strcmp(argv[3], "-") == 0) fout = stdout;
104     else if ( (fout = fopen(argv[3],"wb")) == NULL ) {
105 	fprintf(stderr, "Error opening output speech file: %s: %s.\n",
106          argv[3], strerror(errno));
107 	exit(1);
108     }
109 
110     // Attempt to detect a .c2 file with a header
111     struct c2_header in_hdr;
112     char *ext = strrchr(argv[2], '.');
113     if ((ext != NULL) && (strcmp(ext, ".c2") == 0)) {
114         int nread = fread(&in_hdr,sizeof(in_hdr),1,fin);
115         assert (nread == 1);
116 
117         if (memcmp(in_hdr.magic, c2_file_magic, sizeof(c2_file_magic)) == 0) {
118             fprintf(stderr, "Detected Codec2 file version %d.%d in mode %d\n",
119                     in_hdr.version_major,
120                     in_hdr.version_minor,
121                     in_hdr.mode);
122 
123             mode = in_hdr.mode;
124         } else {
125             fprintf(stderr, "Codec2 file specified but no header detected\n");
126             // Rewind the input file so we can try to decode
127             // based on command line mode selection
128             fseek(fin,0,SEEK_SET);
129         } /* end if - magic detection */
130     } else {
131         // If we got here, we need to honor the command line mode
132         if (strcmp(argv[1],"3200") == 0)
133         mode = CODEC2_MODE_3200;
134         else if (strcmp(argv[1],"2400") == 0)
135         mode = CODEC2_MODE_2400;
136         else if (strcmp(argv[1],"1600") == 0)
137         mode = CODEC2_MODE_1600;
138         else if (strcmp(argv[1],"1400") == 0)
139         mode = CODEC2_MODE_1400;
140         else if (strcmp(argv[1],"1300") == 0)
141         mode = CODEC2_MODE_1300;
142         else if (strcmp(argv[1],"1200") == 0)
143         mode = CODEC2_MODE_1200;
144         else if (strcmp(argv[1],"700C") == 0)
145         mode = CODEC2_MODE_700C;
146         else if (strcmp(argv[1],"450") == 0)
147         mode = CODEC2_MODE_450;
148         else if (strcmp(argv[1],"450PWB") == 0)
149         mode = CODEC2_MODE_450PWB;
150         else {
151         fprintf(stderr, "Error in mode: %s.  Must be 3200, 2400, 1600, 1400, 1300, 1200, 700C, 450, or 450PWB\n", argv[1]);
152         exit(1);
153         }
154         bit_rate = atoi(argv[1]);
155     }; /* end if - extension / header detection */
156 
157     error_mode = NONE;
158     ber = 0.0;
159     burst_length = burst_period = 0.0;
160     burst_timer = 0.0;
161     natural = softdec = bitperchar = 0;
162     report_energy = 0;
163 #ifdef DUMP
164     dump = 0;
165 #endif
166 
167     codec2 = codec2_create(mode);
168     assert(codec2 != NULL);
169     nsam = codec2_samples_per_frame(codec2);
170     nbit = codec2_bits_per_frame(codec2);
171     buf = (short*)malloc(nsam*sizeof(short));
172     nbyte = (nbit + 7) / 8;
173     bits = (unsigned char*)malloc(nbyte*sizeof(char));
174     softdec_bits = (float*)malloc(nbit*sizeof(float));
175     bitperchar_bits = (char*)malloc(nbit*sizeof(char));
176     frames = bit_errors = bits_proc = 0;
177     nstart_bit = 0;
178     nend_bit = nbit-1;
179 
180     while(1) {
181         int option_index = 0;
182         int opt = getopt_long(argc, argv, opt_string,
183                     long_options, &option_index);
184         if (opt == -1)
185             break;
186 
187         switch (opt) {
188         case 0:
189             if(strcmp(long_options[option_index].name, "ber") == 0) {
190                 ber = atof(optarg);
191                 error_mode = UNIFORM;
192             } else if(strcmp(long_options[option_index].name, "startbit") == 0) {
193 	        nstart_bit = atoi(optarg);
194             } else if(strcmp(long_options[option_index].name, "endbit") == 0) {
195 	        nend_bit = atoi(optarg);
196             } else if(strcmp(long_options[option_index].name, "berfile") == 0) {
197 	        if ((fber = fopen(optarg,"wt")) == NULL) {
198 	            fprintf(stderr, "Error opening BER file: %s %s.\n",
199                             optarg, strerror(errno));
200                     exit(1);
201                 }
202 
203             }
204             #ifdef DUMP
205             else if(strcmp(long_options[option_index].name, "dump") == 0) {
206                 if (dump)
207 	            dump_on(optarg);
208             }
209             #endif
210 	    else if (strcmp(long_options[option_index].name, "energy") == 0) {
211 	        report_energy = 1;
212 	    }
213 	    else if (strcmp(long_options[option_index].name, "loadcb") == 0) {
214                 /* load VQ stage (700C only) */
215                 //fprintf(stderr, "%s\n", optarg+1);
216                 codec2_load_codebook(codec2, atoi(optarg)-1, argv[optind]);
217 	    }
218 	    else if (strcmp(long_options[option_index].name, "loadratek") == 0) {
219                 /* load rate K vectors (by passing quantisation) for 700C VQ tests */
220                 fprintf(stderr, "%s\n", optarg);
221                 f_ratek = fopen(optarg, "rb");
222                 assert(f_ratek != NULL);
223                 user_ratek = codec2_enable_user_ratek(codec2, &K);
224 	    }
225 	    else if (strcmp(long_options[option_index].name, "nopf") == 0) {
226 	        codec2_700c_post_filter(codec2, 0);
227 	    }
228 	    else if (strcmp(long_options[option_index].name, "mlfeat") == 0) {
229 		/* dump machine learning features (700C only) */
230 		codec2_open_mlfeat(codec2, optarg, NULL);
231 	    }
232             break;
233 
234         case 'h':
235             print_help(long_options, num_opts, argv);
236             break;
237 
238         default:
239             /* This will never be reached */
240             break;
241         }
242     }
243     assert(nend_bit <= nbit);
244     codec2_set_natural_or_gray(codec2, !natural);
245     //printf("%d %d\n", nstart_bit, nend_bit);
246 
247     //fprintf(stderr, "softdec: %d natural: %d\n", softdec, natural);
248     if (softdec) {
249         ret = (fread(softdec_bits, sizeof(float), nbit, fin) == (size_t)nbit);
250     }
251     if (bitperchar) {
252         ret = (fread(bitperchar_bits, sizeof(char), nbit, fin) == (size_t)nbit);
253     }
254     if (!softdec && !bitperchar) {
255         ret = (fread(bits, sizeof(char), nbyte, fin) == (size_t)nbyte);
256     }
257 
258     while(ret) {
259 	frames++;
260 
261         // apply bit errors, MSB of byte 0 is bit 0 in frame, only works in packed mode
262 
263 	if ((error_mode == UNIFORM) || (error_mode == UNIFORM_RANGE)) {
264             assert(softdec == 0);
265 	    for(i=nstart_bit; i<nend_bit+1; i++) {
266 		r = (float)rand()/RAND_MAX;
267 		if (r < ber) {
268 		    byte = i/8;
269 		    //printf("nbyte %d nbit %d i %d byte %d bits[%d] 0x%0x ", nbyte, nbit, i, byte, byte, bits[byte]);
270 		    mask = 1 << (7 - i + byte*8);
271                     bits[byte] ^= mask;
272 		    //printf("shift: %d mask: 0x%0x bits[%d] 0x%0x\n", 7 - i + byte*8, mask, byte, bits[byte] );
273 		    bit_errors++;
274  		}
275                 bits_proc++;
276 	    }
277 	}
278 
279 	if (error_mode == TWO_STATE) {
280             assert(softdec == 0);
281             burst_timer += (float)nbit/bit_rate;
282             fprintf(stderr, "burst_timer: %f  state: %d\n", burst_timer, state);
283 
284             next_state = state;
285             switch(state) {
286             case 0:
287 
288                 /* clear channel state - no bit errors */
289 
290                 if (burst_timer > (burst_period - burst_length))
291                     next_state = 1;
292                 break;
293 
294             case 1:
295 
296                 /* burst error state - 50% bit error rate */
297 
298                 for(i=nstart_bit; i<nend_bit+1; i++) {
299                     r = (float)rand()/RAND_MAX;
300                     if (r < 0.5) {
301                         byte = i/8;
302                         bits[byte] ^= 1 << (7 - i + byte*8);
303                         bit_errors++;
304                     }
305                     bits_proc++;
306 		}
307 
308                 if (burst_timer > burst_period) {
309                     burst_timer = 0.0;
310                     next_state = 0;
311                 }
312                 break;
313 
314 	    }
315 
316             state = next_state;
317         }
318 
319         if (fber != NULL) {
320             if (fread(&ber_est, sizeof(float), 1, fber) != 1) {
321                 fprintf(stderr, "ran out of BER estimates!\n");
322                 exit(1);
323             }
324             //fprintf(stderr, "ber_est: %f\n", ber_est);
325         }
326         else
327             ber_est = 0.0;
328 
329         if (softdec) {
330             /* pack bits, MSB received first  */
331 
332             bit = 7; byte = 0;
333             memset(bits, 0, nbyte);
334             for(i=0; i<nbit; i++) {
335                 bits[byte] |= ((softdec_bits[i] < 0.0) << bit);
336                 bit--;
337                 if (bit < 0) {
338                     bit = 7;
339                     byte++;
340                 }
341             }
342             codec2_set_softdec(codec2, softdec_bits);
343         }
344 
345         if (bitperchar) {
346             /* pack bits, MSB received first  */
347 
348             bit = 7; byte = 0;
349             memset(bits, 0, nbyte);
350             for(i=0; i<nbit; i++) {
351                 bits[byte] |= bitperchar_bits[i] << bit;
352                 bit--;
353                 if (bit < 0) {
354                     bit = 7;
355                     byte++;
356                 }
357             }
358         }
359 
360         if (report_energy)
361            fprintf(stderr, "Energy: %1.3f\n", codec2_get_energy(codec2, bits));
362 
363         if (f_ratek != NULL)
364             ret = fread(user_ratek, sizeof(float), K, f_ratek);
365 
366     	codec2_decode_ber(codec2, buf, bits, ber_est);
367      	fwrite(buf, sizeof(short), nsam, fout);
368 
369 	    //if this is in a pipeline, we probably don't want the usual
370         //buffering to occur
371 
372         if (fout == stdout) fflush(stdout);
373 
374         if (softdec) {
375             ret = (fread(softdec_bits, sizeof(float), nbit, fin) == (size_t)nbit);
376         }
377         if (bitperchar) {
378             ret = (fread(bitperchar_bits, sizeof(char), nbit, fin) == (size_t)nbit);
379         }
380         if (!softdec && !bitperchar) {
381             ret = (fread(bits, sizeof(char), nbyte, fin) == (size_t)nbyte);
382         }
383     }
384 
385     if (error_mode)
386 	fprintf(stderr, "actual BER: %1.3f\n", (float)bit_errors/bits_proc);
387 
388     codec2_destroy(codec2);
389 
390     free(buf);
391     free(bits);
392     free(softdec_bits);
393     free(bitperchar_bits);
394     fclose(fin);
395     fclose(fout);
396     if (fber != NULL) {
397       fclose(fber);
398     }
399 
400     return 0;
401 }
402 
print_help(const struct option * long_options,int num_opts,char * argv[])403 void print_help(const struct option* long_options, int num_opts, char* argv[])
404 {
405 	int i;
406 	char *option_parameters;
407 	fprintf(stderr, "\nc2dec - Codec 2 decoder and bit error simulation program\n"
408 		"usage: %s 3200|2400|1600|1400|1300|1200|700C|450|450PWB InputFile OutputRawFile [OPTIONS]\n\n"
409                 "Options:\n", argv[0]);
410         for(i=0; i<num_opts-1; i++) {
411 		if(long_options[i].has_arg == no_argument) {
412 			option_parameters="";
413 		} else if (strcmp("ber", long_options[i].name) == 0) {
414 			option_parameters = " BER";
415 		} else if (strcmp("startbit", long_options[i].name) == 0) {
416 			option_parameters = " startBit";
417 		} else if (strcmp("endbit", long_options[i].name) == 0) {
418 			option_parameters = " endBit";
419 		} else if (strcmp("berfile", long_options[i].name) == 0) {
420 			option_parameters = " berFileName";
421 		} else if (strcmp("dump", long_options[i].name) == 0) {
422 			option_parameters = " dumpFilePrefix";
423 		} else if (strcmp("lspEWov", long_options[i].name) == 0) {
424 			option_parameters = " featureFileName";
425 		} else {
426 			option_parameters = " <UNDOCUMENTED parameter>";
427 		}
428 		fprintf(stderr, "\t--%s%s\n", long_options[i].name, option_parameters);
429 	}
430 	exit(1);
431 }
432