Mercurial > hg > sv-dependency-builds
comparison src/libvorbis-1.3.3/vq/bookutil.c @ 1:05aa0afa9217
Bring in flac, ogg, vorbis
author | Chris Cannam |
---|---|
date | Tue, 19 Mar 2013 17:37:49 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:c7265573341e | 1:05aa0afa9217 |
---|---|
1 /******************************************************************** | |
2 * * | |
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |
7 * * | |
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * | |
9 * by the Xiph.Org Foundation http://www.xiph.org/ * | |
10 * * | |
11 ******************************************************************** | |
12 | |
13 function: utility functions for loading .vqh and .vqd files | |
14 last mod: $Id: bookutil.c 16959 2010-03-10 16:03:11Z xiphmont $ | |
15 | |
16 ********************************************************************/ | |
17 | |
18 #include <stdlib.h> | |
19 #include <stdio.h> | |
20 #include <math.h> | |
21 #include <string.h> | |
22 #include <errno.h> | |
23 #include "bookutil.h" | |
24 | |
25 int _best(codebook *book, float *a, int step){ | |
26 | |
27 int dim=book->dim; | |
28 int i,j,o; | |
29 int minval=book->minval; | |
30 int del=book->delta; | |
31 int qv=book->quantvals; | |
32 int ze=(qv>>1); | |
33 int index=0; | |
34 /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */ | |
35 | |
36 if(del!=1){ | |
37 for(i=0,o=step*(dim-1);i<dim;i++,o-=step){ | |
38 int v = ((int)rint(a[o])-minval+(del>>1))/del; | |
39 int m = (v<ze ? ((ze-v)<<1)-1 : ((v-ze)<<1)); | |
40 index = index*qv+ (m<0?0:(m>=qv?qv-1:m)); | |
41 } | |
42 }else{ | |
43 for(i=0,o=step*(dim-1);i<dim;i++,o-=step){ | |
44 int v = (int)rint(a[o])-minval; | |
45 int m = (v<ze ? ((ze-v)<<1)-1 : ((v-ze)<<1)); | |
46 index = index*qv+ (m<0?0:(m>=qv?qv-1:m)); | |
47 } | |
48 } | |
49 | |
50 if(book->c->lengthlist[index]<=0){ | |
51 const static_codebook *c=book->c; | |
52 int best=-1; | |
53 /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */ | |
54 int e[8]={0,0,0,0,0,0,0,0}; | |
55 int maxval = book->minval + book->delta*(book->quantvals-1); | |
56 for(i=0;i<book->entries;i++){ | |
57 if(c->lengthlist[i]>0){ | |
58 float this=0; | |
59 for(j=0;j<dim;j++){ | |
60 float val=(e[j]-a[j*step]); | |
61 this+=val*val; | |
62 } | |
63 if(best==-1 || this<best){ | |
64 best=this; | |
65 index=i; | |
66 } | |
67 } | |
68 /* assumes the value patterning created by the tools in vq/ */ | |
69 j=0; | |
70 while(e[j]>=maxval) | |
71 e[j++]=0; | |
72 if(e[j]>=0) | |
73 e[j]+=book->delta; | |
74 e[j]= -e[j]; | |
75 } | |
76 } | |
77 | |
78 return index; | |
79 } | |
80 | |
81 /* A few little utils for reading files */ | |
82 /* read a line. Use global, persistent buffering */ | |
83 static char *linebuffer=NULL; | |
84 static int lbufsize=0; | |
85 char *get_line(FILE *in){ | |
86 long sofar=0; | |
87 if(feof(in))return NULL; | |
88 | |
89 while(1){ | |
90 int gotline=0; | |
91 | |
92 while(!gotline){ | |
93 if(sofar+1>=lbufsize){ | |
94 if(!lbufsize){ | |
95 lbufsize=1024; | |
96 linebuffer=_ogg_malloc(lbufsize); | |
97 }else{ | |
98 lbufsize*=2; | |
99 linebuffer=_ogg_realloc(linebuffer,lbufsize); | |
100 } | |
101 } | |
102 { | |
103 long c=fgetc(in); | |
104 switch(c){ | |
105 case EOF: | |
106 if(sofar==0)return(NULL); | |
107 /* fallthrough correct */ | |
108 case '\n': | |
109 linebuffer[sofar]='\0'; | |
110 gotline=1; | |
111 break; | |
112 default: | |
113 linebuffer[sofar++]=c; | |
114 linebuffer[sofar]='\0'; | |
115 break; | |
116 } | |
117 } | |
118 } | |
119 | |
120 if(linebuffer[0]=='#'){ | |
121 sofar=0; | |
122 }else{ | |
123 return(linebuffer); | |
124 } | |
125 } | |
126 } | |
127 | |
128 /* read the next numerical value from the given file */ | |
129 static char *value_line_buff=NULL; | |
130 | |
131 int get_line_value(FILE *in,float *value){ | |
132 char *next; | |
133 | |
134 if(!value_line_buff)return(-1); | |
135 | |
136 *value=strtod(value_line_buff, &next); | |
137 if(next==value_line_buff){ | |
138 value_line_buff=NULL; | |
139 return(-1); | |
140 }else{ | |
141 value_line_buff=next; | |
142 while(*value_line_buff>44)value_line_buff++; | |
143 if(*value_line_buff==44)value_line_buff++; | |
144 return(0); | |
145 } | |
146 } | |
147 | |
148 int get_next_value(FILE *in,float *value){ | |
149 while(1){ | |
150 if(get_line_value(in,value)){ | |
151 value_line_buff=get_line(in); | |
152 if(!value_line_buff)return(-1); | |
153 }else{ | |
154 return(0); | |
155 } | |
156 } | |
157 } | |
158 | |
159 int get_next_ivalue(FILE *in,long *ivalue){ | |
160 float value; | |
161 int ret=get_next_value(in,&value); | |
162 *ivalue=value; | |
163 return(ret); | |
164 } | |
165 | |
166 static float sequence_base=0.f; | |
167 static int v_sofar=0; | |
168 void reset_next_value(void){ | |
169 value_line_buff=NULL; | |
170 sequence_base=0.f; | |
171 v_sofar=0; | |
172 } | |
173 | |
174 char *setup_line(FILE *in){ | |
175 reset_next_value(); | |
176 value_line_buff=get_line(in); | |
177 return(value_line_buff); | |
178 } | |
179 | |
180 | |
181 int get_vector(codebook *b,FILE *in,int start, int n,float *a){ | |
182 int i; | |
183 const static_codebook *c=b->c; | |
184 | |
185 while(1){ | |
186 | |
187 if(v_sofar==n || get_line_value(in,a)){ | |
188 reset_next_value(); | |
189 if(get_next_value(in,a)) | |
190 break; | |
191 for(i=0;i<start;i++){ | |
192 sequence_base=*a; | |
193 get_line_value(in,a); | |
194 } | |
195 } | |
196 | |
197 for(i=1;i<c->dim;i++) | |
198 if(get_line_value(in,a+i)) | |
199 break; | |
200 | |
201 if(i==c->dim){ | |
202 float temp=a[c->dim-1]; | |
203 for(i=0;i<c->dim;i++)a[i]-=sequence_base; | |
204 if(c->q_sequencep)sequence_base=temp; | |
205 v_sofar++; | |
206 return(0); | |
207 } | |
208 sequence_base=0.f; | |
209 } | |
210 | |
211 return(-1); | |
212 } | |
213 | |
214 /* read lines fromt he beginning until we find one containing the | |
215 specified string */ | |
216 char *find_seek_to(FILE *in,char *s){ | |
217 rewind(in); | |
218 while(1){ | |
219 char *line=get_line(in); | |
220 if(line){ | |
221 if(strstr(line,s)) | |
222 return(line); | |
223 }else | |
224 return(NULL); | |
225 } | |
226 } | |
227 | |
228 | |
229 /* this reads the format as written by vqbuild/latticebuild; innocent | |
230 (legal) tweaking of the file that would not affect its valid | |
231 header-ness will break this routine */ | |
232 | |
233 codebook *codebook_load(char *filename){ | |
234 codebook *b=_ogg_calloc(1,sizeof(codebook)); | |
235 static_codebook *c=(static_codebook *)(b->c=_ogg_calloc(1,sizeof(static_codebook))); | |
236 int quant_to_read=0; | |
237 FILE *in=fopen(filename,"r"); | |
238 char *line; | |
239 long i; | |
240 | |
241 if(in==NULL){ | |
242 fprintf(stderr,"Couldn't open codebook %s\n",filename); | |
243 exit(1); | |
244 } | |
245 | |
246 /* find the codebook struct */ | |
247 find_seek_to(in,"static const static_codebook "); | |
248 | |
249 /* get the major important values */ | |
250 line=get_line(in); | |
251 if(sscanf(line,"%ld, %ld,", | |
252 &(c->dim),&(c->entries))!=2){ | |
253 fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line); | |
254 exit(1); | |
255 } | |
256 line=get_line(in); | |
257 line=get_line(in); | |
258 if(sscanf(line,"%d, %ld, %ld, %d, %d,", | |
259 &(c->maptype),&(c->q_min),&(c->q_delta),&(c->q_quant), | |
260 &(c->q_sequencep))!=5){ | |
261 fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line); | |
262 exit(1); | |
263 } | |
264 | |
265 switch(c->maptype){ | |
266 case 0: | |
267 quant_to_read=0; | |
268 break; | |
269 case 1: | |
270 quant_to_read=_book_maptype1_quantvals(c); | |
271 break; | |
272 case 2: | |
273 quant_to_read=c->entries*c->dim; | |
274 break; | |
275 } | |
276 | |
277 /* load the quantized entries */ | |
278 find_seek_to(in,"static const long _vq_quantlist_"); | |
279 reset_next_value(); | |
280 c->quantlist=_ogg_malloc(sizeof(long)*quant_to_read); | |
281 for(i=0;i<quant_to_read;i++) | |
282 if(get_next_ivalue(in,c->quantlist+i)){ | |
283 fprintf(stderr,"out of data while reading codebook %s\n",filename); | |
284 exit(1); | |
285 } | |
286 | |
287 /* load the lengthlist */ | |
288 find_seek_to(in,"_lengthlist"); | |
289 reset_next_value(); | |
290 c->lengthlist=_ogg_malloc(sizeof(long)*c->entries); | |
291 for(i=0;i<c->entries;i++) | |
292 if(get_next_ivalue(in,c->lengthlist+i)){ | |
293 fprintf(stderr,"out of data while reading codebook %s\n",filename); | |
294 exit(1); | |
295 } | |
296 | |
297 /* got it all */ | |
298 fclose(in); | |
299 | |
300 vorbis_book_init_encode(b,c); | |
301 b->valuelist=_book_unquantize(c,c->entries,NULL); | |
302 | |
303 return(b); | |
304 } | |
305 | |
306 void spinnit(char *s,int n){ | |
307 static int p=0; | |
308 static long lasttime=0; | |
309 long test; | |
310 struct timeval thistime; | |
311 | |
312 gettimeofday(&thistime,NULL); | |
313 test=thistime.tv_sec*10+thistime.tv_usec/100000; | |
314 if(lasttime!=test){ | |
315 lasttime=test; | |
316 | |
317 fprintf(stderr,"%s%d ",s,n); | |
318 | |
319 p++;if(p>3)p=0; | |
320 switch(p){ | |
321 case 0: | |
322 fprintf(stderr,"| \r"); | |
323 break; | |
324 case 1: | |
325 fprintf(stderr,"/ \r"); | |
326 break; | |
327 case 2: | |
328 fprintf(stderr,"- \r"); | |
329 break; | |
330 case 3: | |
331 fprintf(stderr,"\\ \r"); | |
332 break; | |
333 } | |
334 fflush(stderr); | |
335 } | |
336 } | |
337 | |
338 void build_tree_from_lengths(int vals, long *hist, long *lengths){ | |
339 int i,j; | |
340 long *membership=_ogg_malloc(vals*sizeof(long)); | |
341 long *histsave=alloca(vals*sizeof(long)); | |
342 memcpy(histsave,hist,vals*sizeof(long)); | |
343 | |
344 for(i=0;i<vals;i++)membership[i]=i; | |
345 | |
346 /* find codeword lengths */ | |
347 /* much more elegant means exist. Brute force n^2, minimum thought */ | |
348 for(i=vals;i>1;i--){ | |
349 int first=-1,second=-1; | |
350 long least=-1; | |
351 | |
352 spinnit("building... ",i); | |
353 | |
354 /* find the two nodes to join */ | |
355 for(j=0;j<vals;j++) | |
356 if(least==-1 || hist[j]<=least){ | |
357 least=hist[j]; | |
358 first=membership[j]; | |
359 } | |
360 least=-1; | |
361 for(j=0;j<vals;j++) | |
362 if((least==-1 || hist[j]<=least) && membership[j]!=first){ | |
363 least=hist[j]; | |
364 second=membership[j]; | |
365 } | |
366 if(first==-1 || second==-1){ | |
367 fprintf(stderr,"huffman fault; no free branch\n"); | |
368 exit(1); | |
369 } | |
370 | |
371 /* join them */ | |
372 least=hist[first]+hist[second]; | |
373 for(j=0;j<vals;j++) | |
374 if(membership[j]==first || membership[j]==second){ | |
375 membership[j]=first; | |
376 hist[j]=least; | |
377 lengths[j]++; | |
378 } | |
379 } | |
380 for(i=0;i<vals-1;i++) | |
381 if(membership[i]!=membership[i+1]){ | |
382 fprintf(stderr,"huffman fault; failed to build single tree\n"); | |
383 exit(1); | |
384 } | |
385 | |
386 /* for sanity check purposes: how many bits would it have taken to | |
387 encode the training set? */ | |
388 { | |
389 long bitsum=0; | |
390 long samples=0; | |
391 for(i=0;i<vals;i++){ | |
392 bitsum+=(histsave[i]-1)*lengths[i]; | |
393 samples+=histsave[i]-1; | |
394 } | |
395 | |
396 if(samples){ | |
397 fprintf(stderr,"\rTotal samples in training set: %ld \n",samples); | |
398 fprintf(stderr,"\rTotal bits used to represent training set: %ld\n", | |
399 bitsum); | |
400 } | |
401 } | |
402 | |
403 free(membership); | |
404 } | |
405 | |
406 /* wrap build_tree_from_lengths to allow zero entries in the histogram */ | |
407 void build_tree_from_lengths0(int vals, long *hist, long *lengths){ | |
408 | |
409 /* pack the 'sparse' hit list into a dense list, then unpack | |
410 the lengths after the build */ | |
411 | |
412 int upper=0,i; | |
413 long *lengthlist=_ogg_calloc(vals,sizeof(long)); | |
414 long *newhist=alloca(vals*sizeof(long)); | |
415 | |
416 for(i=0;i<vals;i++) | |
417 if(hist[i]>0) | |
418 newhist[upper++]=hist[i]; | |
419 | |
420 if(upper != vals){ | |
421 fprintf(stderr,"\rEliminating %d unused entries; %d entries remain\n", | |
422 vals-upper,upper); | |
423 } | |
424 | |
425 build_tree_from_lengths(upper,newhist,lengthlist); | |
426 | |
427 upper=0; | |
428 for(i=0;i<vals;i++) | |
429 if(hist[i]>0) | |
430 lengths[i]=lengthlist[upper++]; | |
431 else | |
432 lengths[i]=0; | |
433 | |
434 free(lengthlist); | |
435 } | |
436 | |
437 void write_codebook(FILE *out,char *name,const static_codebook *c){ | |
438 int i,j,k; | |
439 | |
440 /* save the book in C header form */ | |
441 | |
442 /* first, the static vectors, then the book structure to tie it together. */ | |
443 /* quantlist */ | |
444 if(c->quantlist){ | |
445 long vals=(c->maptype==1?_book_maptype1_quantvals(c):c->entries*c->dim); | |
446 fprintf(out,"static const long _vq_quantlist_%s[] = {\n",name); | |
447 for(j=0;j<vals;j++){ | |
448 fprintf(out,"\t%ld,\n",c->quantlist[j]); | |
449 } | |
450 fprintf(out,"};\n\n"); | |
451 } | |
452 | |
453 /* lengthlist */ | |
454 fprintf(out,"static const long _vq_lengthlist_%s[] = {\n",name); | |
455 for(j=0;j<c->entries;){ | |
456 fprintf(out,"\t"); | |
457 for(k=0;k<16 && j<c->entries;k++,j++) | |
458 fprintf(out,"%2ld,",c->lengthlist[j]); | |
459 fprintf(out,"\n"); | |
460 } | |
461 fprintf(out,"};\n\n"); | |
462 | |
463 /* tie it all together */ | |
464 | |
465 fprintf(out,"static const static_codebook %s = {\n",name); | |
466 | |
467 fprintf(out,"\t%ld, %ld,\n",c->dim,c->entries); | |
468 fprintf(out,"\t(long *)_vq_lengthlist_%s,\n",name); | |
469 fprintf(out,"\t%d, %ld, %ld, %d, %d,\n", | |
470 c->maptype,c->q_min,c->q_delta,c->q_quant,c->q_sequencep); | |
471 if(c->quantlist) | |
472 fprintf(out,"\t(long *)_vq_quantlist_%s,\n",name); | |
473 else | |
474 fprintf(out,"\tNULL,\n"); | |
475 | |
476 fprintf(out,"\t0\n};\n\n"); | |
477 } |