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