]>
Commit | Line | Data |
---|---|---|
964dd0bc JW |
1 | /* JOrbis |
2 | * Copyright (C) 2000 ymnk, JCraft,Inc. | |
3 | * | |
4 | * Written by: 2000 ymnk<ymnk@jcraft.com> | |
5 | * | |
6 | * Many thanks to | |
7 | * Monty <monty@xiph.org> and | |
8 | * The XIPHOPHORUS Company http://www.xiph.org/ . | |
9 | * JOrbis has been based on their awesome works, Vorbis codec. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Library General Public License | |
13 | * as published by the Free Software Foundation; either version 2 of | |
14 | * the License, or (at your option) any later version. | |
15 | ||
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | * GNU Library General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Library General Public | |
22 | * License along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 | */ | |
25 | ||
26 | package com.jcraft.jorbis; | |
27 | ||
28 | import com.jcraft.jogg.*; | |
29 | ||
30 | class Floor0 extends FuncFloor{ | |
31 | ||
32 | void pack(Object i, Buffer opb){ | |
33 | InfoFloor0 info=(InfoFloor0)i; | |
34 | opb.write(info.order,8); | |
35 | opb.write(info.rate,16); | |
36 | opb.write(info.barkmap,16); | |
37 | opb.write(info.ampbits,6); | |
38 | opb.write(info.ampdB,8); | |
39 | opb.write(info.numbooks-1,4); | |
40 | for(int j=0;j<info.numbooks;j++) | |
41 | opb.write(info.books[j],8); | |
42 | } | |
43 | ||
44 | Object unpack(Info vi , Buffer opb){ | |
45 | InfoFloor0 info=new InfoFloor0(); | |
46 | info.order=opb.read(8); | |
47 | info.rate=opb.read(16); | |
48 | info.barkmap=opb.read(16); | |
49 | info.ampbits=opb.read(6); | |
50 | info.ampdB=opb.read(8); | |
51 | info.numbooks=opb.read(4)+1; | |
52 | ||
53 | if((info.order<1)|| | |
54 | (info.rate<1)|| | |
55 | (info.barkmap<1)|| | |
56 | (info.numbooks<1)){ | |
57 | //free_info(info); | |
58 | return(null); | |
59 | } | |
60 | ||
61 | for(int j=0;j<info.numbooks;j++){ | |
62 | info.books[j]=opb.read(8); | |
63 | if(info.books[j]<0 || info.books[j]>=vi.books){ | |
64 | //free_info(info); | |
65 | return(null); | |
66 | } | |
67 | } | |
68 | return(info); | |
69 | // err_out: | |
70 | // free_info(info); | |
71 | // return(NULL); | |
72 | } | |
73 | Object look(DspState vd, InfoMode mi, Object i){ | |
74 | float scale; | |
75 | Info vi=vd.vi; | |
76 | InfoFloor0 info=(InfoFloor0)i; | |
77 | LookFloor0 look=new LookFloor0(); | |
78 | look.m=info.order; | |
79 | look.n=vi.blocksizes[mi.blockflag]/2; | |
80 | look.ln=info.barkmap; | |
81 | look.vi=info; | |
82 | look.lpclook.init(look.ln,look.m); | |
83 | ||
84 | // we choose a scaling constant so that: | |
85 | // floor(bark(rate/2-1)*C)=mapped-1 | |
86 | // floor(bark(rate/2)*C)=mapped | |
87 | scale=look.ln/toBARK((float)(info.rate/2.)); | |
88 | ||
89 | // the mapping from a linear scale to a smaller bark scale is | |
90 | // straightforward. We do *not* make sure that the linear mapping | |
91 | // does not skip bark-scale bins; the decoder simply skips them and | |
92 | // the encoder may do what it wishes in filling them. They're | |
93 | // necessary in some mapping combinations to keep the scale spacing | |
94 | // accurate | |
95 | look.linearmap=new int[look.n]; | |
96 | for(int j=0;j<look.n;j++){ | |
97 | int val=(int)Math.floor(toBARK((float)((info.rate/2.)/look.n*j)) | |
98 | *scale); // bark numbers represent band edges | |
99 | if(val>=look.ln)val=look.ln; // guard against the approximation | |
100 | look.linearmap[j]=val; | |
101 | } | |
102 | return look; | |
103 | } | |
104 | ||
105 | static float toBARK(float f){ | |
106 | return (float)(13.1*Math.atan(.00074*(f))+2.24*Math.atan((f)*(f)*1.85e-8)+1e-4*(f)); | |
107 | } | |
108 | ||
109 | Object state(Object i){ | |
110 | EchstateFloor0 state=new EchstateFloor0(); | |
111 | InfoFloor0 info=(InfoFloor0)i; | |
112 | ||
113 | // a safe size if usually too big (dim==1) | |
114 | state.codewords=new int[info.order]; | |
115 | state.curve=new float[info.barkmap]; | |
116 | state.frameno=-1; | |
117 | return(state); | |
118 | } | |
119 | void free_info(Object i){} | |
120 | void free_look(Object i){} | |
121 | void free_state(Object vs){} | |
122 | int forward(Block vb, Object i, float[] in, float[] out, Object vs){return 0;} | |
123 | ||
124 | float[] lsp=null; | |
125 | int inverse(Block vb, Object i, float[] out){ | |
126 | //System.err.println("Floor0.inverse "+i.getClass()+"]"); | |
127 | LookFloor0 look=(LookFloor0)i; | |
128 | InfoFloor0 info=look.vi; | |
129 | int ampraw=vb.opb.read(info.ampbits); | |
130 | if(ampraw>0){ // also handles the -1 out of data case | |
131 | int maxval=(1<<info.ampbits)-1; | |
132 | float amp=(float)ampraw/maxval*info.ampdB; | |
133 | int booknum=vb.opb.read(ilog(info.numbooks)); | |
134 | ||
135 | if(booknum!=-1 && booknum<info.numbooks){ | |
136 | ||
137 | synchronized(this){ | |
138 | if(lsp==null||lsp.length<look.m){ | |
139 | lsp=new float[look.m]; | |
140 | } | |
141 | else{ | |
142 | for(int j=0; j<look.m; j++)lsp[j]=0.f; | |
143 | } | |
144 | ||
145 | CodeBook b=vb.vd.fullbooks[info.books[booknum]]; | |
146 | float last=0.f; | |
147 | ||
148 | //memset(out,0,sizeof(float)*look->m); | |
149 | for(int j=0; j<look.m; j++)out[j]=0.0f; | |
150 | ||
151 | for(int j=0;j<look.m;j+=b.dim){ | |
152 | if(b.decodevs(lsp, j, vb.opb, 1, -1)==-1){ | |
153 | //goto eop; | |
154 | // memset(out,0,sizeof(float)*look->n); | |
155 | for(int k=0; k<look.n; k++)out[k]=0.0f; | |
156 | return(0); | |
157 | } | |
158 | } | |
159 | for(int j=0;j<look.m;){ | |
160 | for(int k=0;k<b.dim;k++,j++)lsp[j]+=last; | |
161 | last=lsp[j-1]; | |
162 | } | |
163 | // take the coefficients back to a spectral envelope curve | |
164 | /* | |
165 | lsp_to_lpc(out,out,look.m); | |
166 | lpc_to_curve(out,out,amp,look,"",0); | |
167 | for(int j=0;j<look.n;j++){ | |
168 | out[j]=fromdB(out[j]-info.ampdB); | |
169 | } | |
170 | */ | |
171 | Lsp.lsp_to_curve(out,look.linearmap,look.n,look.ln, | |
172 | lsp,look.m,amp,info.ampdB); | |
173 | ||
174 | return(1); | |
175 | } | |
176 | } | |
177 | } | |
178 | // eop: | |
179 | // memset(out,0,sizeof(float)*look->n); | |
180 | return(0); | |
181 | } | |
182 | ||
183 | Object inverse1(Block vb, Object i, Object memo){ | |
184 | //System.err.println("Floor0.inverse "+i.getClass()+"]"); | |
185 | LookFloor0 look=(LookFloor0)i; | |
186 | InfoFloor0 info=look.vi; | |
187 | float[] lsp=null; | |
188 | if(memo instanceof float[]){ | |
189 | lsp=(float[])memo; | |
190 | } | |
191 | ||
192 | int ampraw=vb.opb.read(info.ampbits); | |
193 | if(ampraw>0){ // also handles the -1 out of data case | |
194 | int maxval=(1<<info.ampbits)-1; | |
195 | float amp=(float)ampraw/maxval*info.ampdB; | |
196 | int booknum=vb.opb.read(ilog(info.numbooks)); | |
197 | ||
198 | if(booknum!=-1 && booknum<info.numbooks){ | |
199 | CodeBook b=vb.vd.fullbooks[info.books[booknum]]; | |
200 | float last=0.f; | |
201 | ||
202 | if(lsp==null||lsp.length<look.m+1){ | |
203 | lsp=new float[look.m+1]; | |
204 | } | |
205 | else{ | |
206 | for(int j=0; j<lsp.length; j++)lsp[j]=0.f; | |
207 | } | |
208 | ||
209 | for(int j=0;j<look.m;j+=b.dim){ | |
210 | if(b.decodev_set(lsp, j, vb.opb, b.dim)==-1){ | |
211 | //goto eop; | |
212 | return(null); | |
213 | } | |
214 | } | |
215 | ||
216 | for(int j=0;j<look.m;){ | |
217 | for(int k=0;k<b.dim;k++,j++)lsp[j]+=last; | |
218 | last=lsp[j-1]; | |
219 | } | |
220 | lsp[look.m]=amp; | |
221 | return(lsp); | |
222 | } | |
223 | } | |
224 | // eop: | |
225 | return(null); | |
226 | } | |
227 | ||
228 | int inverse2(Block vb, Object i, Object memo, float[] out){ | |
229 | //System.err.println("Floor0.inverse "+i.getClass()+"]"); | |
230 | LookFloor0 look=(LookFloor0)i; | |
231 | InfoFloor0 info=look.vi; | |
232 | ||
233 | if(memo!=null){ | |
234 | float[] lsp=(float[])memo; | |
235 | float amp=lsp[look.m]; | |
236 | ||
237 | Lsp.lsp_to_curve(out,look.linearmap,look.n,look.ln, | |
238 | lsp,look.m,amp,info.ampdB); | |
239 | return(1); | |
240 | } | |
241 | // eop: | |
242 | // memset(out,0,sizeof(float)*look->n); | |
243 | for(int j=0; j<look.n; j++){ | |
244 | out[j]=0.f; | |
245 | } | |
246 | return(0); | |
247 | } | |
248 | ||
249 | static float fromdB(float x){ | |
250 | return (float)(Math.exp((x)*.11512925)); | |
251 | } | |
252 | private static int ilog(int v){ | |
253 | int ret=0; | |
254 | while(v!=0){ | |
255 | ret++; | |
256 | v>>>=1; | |
257 | } | |
258 | return(ret); | |
259 | } | |
260 | ||
261 | static void lsp_to_lpc(float[] lsp, float[] lpc, int m){ | |
262 | int i,j,m2=m/2; | |
263 | float[] O=new float[m2]; | |
264 | float[] E=new float[m2]; | |
265 | float A; | |
266 | float[] Ae=new float[m2+1]; | |
267 | float[] Ao=new float[m2+1]; | |
268 | float B; | |
269 | float[] Be=new float[m2]; | |
270 | float[] Bo=new float[m2]; | |
271 | float temp; | |
272 | ||
273 | // even/odd roots setup | |
274 | for(i=0;i<m2;i++){ | |
275 | O[i]=(float)(-2.*Math.cos(lsp[i*2])); | |
276 | E[i]=(float)(-2.*Math.cos(lsp[i*2+1])); | |
277 | } | |
278 | ||
279 | // set up impulse response | |
280 | for(j=0;j<m2;j++){ | |
281 | Ae[j]=0.f; | |
282 | Ao[j]=1.f; | |
283 | Be[j]=0.f; | |
284 | Bo[j]=1.f; | |
285 | } | |
286 | Ao[j]=1.f; | |
287 | Ae[j]=1.f; | |
288 | ||
289 | // run impulse response | |
290 | for(i=1;i<m+1;i++){ | |
291 | A=B=0.f; | |
292 | for(j=0;j<m2;j++){ | |
293 | temp=O[j]*Ao[j]+Ae[j]; | |
294 | Ae[j]=Ao[j]; | |
295 | Ao[j]=A; | |
296 | A+=temp; | |
297 | ||
298 | temp=E[j]*Bo[j]+Be[j]; | |
299 | Be[j]=Bo[j]; | |
300 | Bo[j]=B; | |
301 | B+=temp; | |
302 | } | |
303 | lpc[i-1]=(A+Ao[j]+B-Ae[j])/2; | |
304 | Ao[j]=A; | |
305 | Ae[j]=B; | |
306 | } | |
307 | } | |
308 | ||
309 | static void lpc_to_curve(float[] curve, float[] lpc,float amp, | |
310 | LookFloor0 l, String name, int frameno){ | |
311 | // l->m+1 must be less than l->ln, but guard in case we get a bad stream | |
312 | float[] lcurve=new float[Math.max(l.ln*2,l.m*2+2)]; | |
313 | ||
314 | if(amp==0){ | |
315 | //memset(curve,0,sizeof(float)*l->n); | |
316 | for(int j=0; j<l.n; j++)curve[j]=0.0f; | |
317 | return; | |
318 | } | |
319 | l.lpclook.lpc_to_curve(lcurve,lpc,amp); | |
320 | ||
321 | for(int i=0;i<l.n;i++)curve[i]=lcurve[l.linearmap[i]]; | |
322 | } | |
323 | } | |
324 | ||
325 | class InfoFloor0{ | |
326 | int order; | |
327 | int rate; | |
328 | int barkmap; | |
329 | ||
330 | int ampbits; | |
331 | int ampdB; | |
332 | ||
333 | int numbooks; // <= 16 | |
334 | int[] books=new int[16]; | |
335 | } | |
336 | ||
337 | class LookFloor0{ | |
338 | int n; | |
339 | int ln; | |
340 | int m; | |
341 | int[] linearmap; | |
342 | ||
343 | InfoFloor0 vi; | |
344 | Lpc lpclook=new Lpc(); | |
345 | } | |
346 | ||
347 | class EchstateFloor0{ | |
348 | int[] codewords; | |
349 | float[] curve; | |
350 | long frameno; | |
351 | long codes; | |
352 | } |