1 /*---------------------------------------------------------------------------*\
2 
3   FILE........: generate_codebook.c
4   AUTHOR......: Bruce Perens
5   DATE CREATED: 29 Sep 2010
6 
7   Generate header files containing quantisers, runs at compile time.
8 
9 \*---------------------------------------------------------------------------*/
10 
11 /*
12   All rights reserved.
13 
14   This program is free software; you can redistribute it and/or modify
15   it under the terms of the GNU Lesser General Public License version 2.1, as
16   published by the Free Software Foundation.  This program is
17   distributed in the hope that it will be useful, but WITHOUT ANY
18   WARRANTY; without even the implied warranty of MERCHANTABILITY or
19   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
20   License for more details.
21 
22   You should have received a copy of the GNU Lesser General Public License
23   along with this program; if not, see <http://www.gnu.org/licenses/>.
24 */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <math.h>
30 
31 static const char usage[] =
32 "Usage: %s filename array_name [filename ...]\n"
33 "\tCreate C code for codebook tables.\n";
34 
35 static const char format[] =
36 "The table format must be:\n"
37 "\tTwo integers describing the dimensions of the codebook.\n"
38 "\tThen, enough numbers to fill the specified dimensions.\n";
39 
40 static const char header[] =
41 "/* THIS IS A GENERATED FILE. Edit generate_codebook.c and its input */\n\n"
42 "/*\n"
43 " * This intermediary file and the files that used to create it are under \n"
44 " * The LGPL. See the file COPYING.\n"
45 " */\n\n"
46 "#include \"defines.h\"\n\n";
47 
48 struct codebook {
49   unsigned int	k;
50   unsigned int	log2m;
51   unsigned int	m;
52   float * cb;
53 };
54 
55 static void
dump_array(const struct codebook * b,int index)56 dump_array(const struct codebook * b, int index)
57 {
58   int	limit = b->k * b->m;
59   int	i;
60 
61   printf("#ifdef __EMBEDDED__\n");
62   printf("static const float codes%d[] = {\n", index);
63   printf("#else\n");
64   printf("static float codes%d[] = {\n", index);
65   printf("#endif\n");
66   for ( i = 0; i < limit; i++ ) {
67     printf("  %g", b->cb[i]);
68     if ( i < limit - 1 )
69       printf(",");
70 
71     /* organise VQs by rows, looks prettier */
72     if ( ((i+1) % b->k) == 0 )
73 	printf("\n");
74   }
75   printf("};\n");
76 }
77 
78 static void
dump_structure(const struct codebook * b,int index)79 dump_structure(const struct codebook * b, int index)
80 {
81   printf("  {\n");
82   printf("    %d,\n", b->k);
83   printf("    %d,\n", (int)roundf(log(b->m) / log(2)));
84   printf("    %d,\n", b->m);
85   printf("    codes%d\n", index);
86   printf("  }");
87 }
88 
89 float
get_float(FILE * in,const char * name,char ** cursor,char * buffer,int size)90 get_float(FILE * in, const char * name, char * * cursor, char * buffer,
91  int size)
92 {
93   for ( ; ; ) {
94     char *	s = *cursor;
95     char	c;
96 
97     while ( (c = *s) != '\0' && !isdigit(c) && c != '-' && c != '.' )
98       s++;
99 
100     /* Comments start with "#" and continue to the end of the line. */
101     if ( c != '\0' && c != '#' ) {
102       char *	end = 0;
103       float	f = 0;
104 
105       f = strtod(s, &end);
106 
107       if ( end != s )
108         *cursor = end;
109       return f;
110     }
111 
112     if ( fgets(buffer, size, in) == NULL ) {
113       fprintf(stderr, "%s: Format error. %s\n", name, format);
114       exit(1);
115     }
116     *cursor = buffer;
117   }
118 }
119 
120 static struct codebook *
load(FILE * file,const char * name)121 load(FILE * file, const char * name)
122 {
123   char			line[1024];
124   char *		cursor = line;
125   struct codebook *	b = malloc(sizeof(struct codebook));
126   int			i;
127   int			size;
128 
129   *cursor = '\0';
130 
131   b->k = (int)get_float(file, name, &cursor, line, sizeof(line));
132   b->m = (int)get_float(file, name ,&cursor, line, sizeof(line));
133   size = b->k * b->m;
134 
135   b->cb = (float *)malloc(size * sizeof(float));
136 
137   for ( i = 0; i < size; i++ )
138     b->cb[i] = get_float(file, name, &cursor, line, sizeof(line));
139 
140   return b;
141 }
142 
143 int
main(int argc,char ** argv)144 main(int argc, char * * argv)
145 {
146   struct codebook * *	cb = malloc(argc * sizeof(struct codebook *));
147   int			i;
148 
149   if ( argc < 2 ) {
150     fprintf(stderr, usage, argv[0]);
151     fprintf(stderr, format);
152     exit(1);
153   }
154 
155   for ( i = 0; i < argc - 2; i++ ) {
156     FILE *	in = fopen(argv[i + 2], "r");
157 
158     if ( in == NULL ) {
159       perror(argv[i + 2]);
160       exit(1);
161     }
162 
163     cb[i] = load(in, argv[i + 2]);
164 
165     fclose(in);
166   }
167 
168   printf(header);
169   for ( i = 0; i < argc - 2; i++ ) {
170     printf("  /* %s */\n", argv[i + 2]);
171     dump_array(cb[i], i);
172   }
173   printf("\nconst struct lsp_codebook %s[] = {\n", argv[1]);
174   for ( i = 0; i < argc - 2; i++ ) {
175     printf("  /* %s */\n", argv[i + 2]);
176     dump_structure(cb[i], i);
177     printf(",\n");
178   }
179   printf("  { 0, 0, 0, 0 }\n");
180   printf("};\n");
181   for( i = 0; i < argc - 2; i++ ){
182     free(cb[i]->cb);
183     free(cb[i]);
184   }
185   free(cb);
186   return 0;
187 }
188