]>
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 | public class DspState{ | |
29 | static final float M_PI=3.1415926539f; | |
30 | static final int VI_TRANSFORMB=1; | |
31 | static final int VI_WINDOWB=1; | |
32 | ||
33 | int analysisp; | |
34 | Info vi; | |
35 | int modebits; | |
36 | ||
37 | float[][] pcm; | |
38 | //float[][] pcmret; | |
39 | int pcm_storage; | |
40 | int pcm_current; | |
41 | int pcm_returned; | |
42 | ||
43 | float[] multipliers; | |
44 | int envelope_storage; | |
45 | int envelope_current; | |
46 | ||
47 | int eofflag; | |
48 | ||
49 | int lW; | |
50 | int W; | |
51 | int nW; | |
52 | int centerW; | |
53 | ||
54 | long granulepos; | |
55 | long sequence; | |
56 | ||
57 | long glue_bits; | |
58 | long time_bits; | |
59 | long floor_bits; | |
60 | long res_bits; | |
61 | ||
62 | // local lookup storage | |
63 | //!! Envelope ve=new Envelope(); // envelope | |
64 | //float **window[2][2][2]; // block, leadin, leadout, type | |
65 | float[][][][][] window; // block, leadin, leadout, type | |
66 | //vorbis_look_transform **transform[2]; // block, type | |
67 | Object[][] transform; | |
68 | CodeBook[] fullbooks; | |
69 | // backend lookups are tied to the mode, not the backend or naked mapping | |
70 | Object[] mode; | |
71 | ||
72 | // local storage, only used on the encoding side. This way the | |
73 | // application does not need to worry about freeing some packets' | |
74 | // memory and not others'; packet storage is always tracked. | |
75 | // Cleared next call to a _dsp_ function | |
76 | byte[] header; | |
77 | byte[] header1; | |
78 | byte[] header2; | |
79 | ||
80 | public DspState(){ | |
81 | transform=new Object[2][]; | |
82 | window=new float[2][][][][]; | |
83 | window[0]=new float[2][][][]; | |
84 | window[0][0]=new float[2][][]; | |
85 | window[0][1]=new float[2][][]; | |
86 | window[0][0][0]=new float[2][]; | |
87 | window[0][0][1]=new float[2][]; | |
88 | window[0][1][0]=new float[2][]; | |
89 | window[0][1][1]=new float[2][]; | |
90 | window[1]=new float[2][][][]; | |
91 | window[1][0]=new float[2][][]; | |
92 | window[1][1]=new float[2][][]; | |
93 | window[1][0][0]=new float[2][]; | |
94 | window[1][0][1]=new float[2][]; | |
95 | window[1][1][0]=new float[2][]; | |
96 | window[1][1][1]=new float[2][]; | |
97 | } | |
98 | ||
99 | private static int ilog2(int v){ | |
100 | int ret=0; | |
101 | while(v>1){ | |
102 | ret++; | |
103 | v>>>=1; | |
104 | } | |
105 | return(ret); | |
106 | } | |
107 | ||
108 | static float[] window(int type, int window, int left, int right){ | |
109 | float[] ret=new float[window]; | |
110 | switch(type){ | |
111 | case 0: | |
112 | // The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*2pi) | |
113 | { | |
114 | int leftbegin=window/4-left/2; | |
115 | int rightbegin=window-window/4-right/2; | |
116 | ||
117 | for(int i=0;i<left;i++){ | |
118 | float x=(float)((i+.5)/left*M_PI/2.); | |
119 | x=(float)Math.sin(x); | |
120 | x*=x; | |
121 | x*=M_PI/2.; | |
122 | x=(float)Math.sin(x); | |
123 | ret[i+leftbegin]=x; | |
124 | } | |
125 | ||
126 | for(int i=leftbegin+left;i<rightbegin;i++){ | |
127 | ret[i]=1.f; | |
128 | } | |
129 | ||
130 | for(int i=0;i<right;i++){ | |
131 | float x=(float)((right-i-.5)/right*M_PI/2.); | |
132 | x=(float)Math.sin(x); | |
133 | x*=x; | |
134 | x*=M_PI/2.; | |
135 | x=(float)Math.sin(x); | |
136 | ret[i+rightbegin]=x; | |
137 | } | |
138 | } | |
139 | break; | |
140 | default: | |
141 | //free(ret); | |
142 | return(null); | |
143 | } | |
144 | return(ret); | |
145 | } | |
146 | ||
147 | // Analysis side code, but directly related to blocking. Thus it's | |
148 | // here and not in analysis.c (which is for analysis transforms only). | |
149 | // The init is here because some of it is shared | |
150 | ||
151 | int init(Info vi, boolean encp){ | |
152 | //System.err.println("DspState.init: vi="+vi+", encp="+encp); | |
153 | //memset(v,0,sizeof(vorbis_dsp_state)); | |
154 | this.vi=vi; | |
155 | modebits=ilog2(vi.modes); | |
156 | ||
157 | transform[0]=new Object[VI_TRANSFORMB]; | |
158 | transform[1]=new Object[VI_TRANSFORMB]; | |
159 | ||
160 | // MDCT is tranform 0 | |
161 | ||
162 | transform[0][0]=new Mdct(); | |
163 | transform[1][0]=new Mdct(); | |
164 | ((Mdct)transform[0][0]).init(vi.blocksizes[0]); | |
165 | ((Mdct)transform[1][0]).init(vi.blocksizes[1]); | |
166 | ||
167 | window[0][0][0]=new float[VI_WINDOWB][]; | |
168 | window[0][0][1]=window[0][0][0]; | |
169 | window[0][1][0]=window[0][0][0]; | |
170 | window[0][1][1]=window[0][0][0]; | |
171 | window[1][0][0]=new float[VI_WINDOWB][]; | |
172 | window[1][0][1]=new float[VI_WINDOWB][]; | |
173 | window[1][1][0]=new float[VI_WINDOWB][]; | |
174 | window[1][1][1]=new float[VI_WINDOWB][]; | |
175 | ||
176 | for(int i=0;i<VI_WINDOWB;i++){ | |
177 | window[0][0][0][i]= | |
178 | window(i,vi.blocksizes[0],vi.blocksizes[0]/2,vi.blocksizes[0]/2); | |
179 | window[1][0][0][i]= | |
180 | window(i,vi.blocksizes[1],vi.blocksizes[0]/2,vi.blocksizes[0]/2); | |
181 | window[1][0][1][i]= | |
182 | window(i,vi.blocksizes[1],vi.blocksizes[0]/2,vi.blocksizes[1]/2); | |
183 | window[1][1][0][i]= | |
184 | window(i,vi.blocksizes[1],vi.blocksizes[1]/2,vi.blocksizes[0]/2); | |
185 | window[1][1][1][i]= | |
186 | window(i,vi.blocksizes[1],vi.blocksizes[1]/2,vi.blocksizes[1]/2); | |
187 | } | |
188 | ||
189 | // if(encp){ // encode/decode differ here | |
190 | // // finish the codebooks | |
191 | // fullbooks=new CodeBook[vi.books]; | |
192 | // for(int i=0;i<vi.books;i++){ | |
193 | // fullbooks[i]=new CodeBook(); | |
194 | // fullbooks[i].init_encode(vi.book_param[i]); | |
195 | // } | |
196 | // analysisp=1; | |
197 | // } | |
198 | // else{ | |
199 | // finish the codebooks | |
200 | fullbooks=new CodeBook[vi.books]; | |
201 | for(int i=0;i<vi.books;i++){ | |
202 | fullbooks[i]=new CodeBook(); | |
203 | fullbooks[i].init_decode(vi.book_param[i]); | |
204 | } | |
205 | // } | |
206 | ||
207 | // initialize the storage vectors to a decent size greater than the | |
208 | // minimum | |
209 | ||
210 | pcm_storage=8192; // we'll assume later that we have | |
211 | // a minimum of twice the blocksize of | |
212 | // accumulated samples in analysis | |
213 | pcm=new float[vi.channels][]; | |
214 | //pcmret=new float[vi.channels][]; | |
215 | { | |
216 | for(int i=0;i<vi.channels;i++){ | |
217 | pcm[i]=new float[pcm_storage]; | |
218 | } | |
219 | } | |
220 | ||
221 | // all 1 (large block) or 0 (small block) | |
222 | // explicitly set for the sake of clarity | |
223 | lW=0; // previous window size | |
224 | W=0; // current window size | |
225 | ||
226 | // all vector indexes; multiples of samples_per_envelope_step | |
227 | centerW=vi.blocksizes[1]/2; | |
228 | ||
229 | pcm_current=centerW; | |
230 | ||
231 | // initialize all the mapping/backend lookups | |
232 | mode=new Object[vi.modes]; | |
233 | for(int i=0;i<vi.modes;i++){ | |
234 | int mapnum=vi.mode_param[i].mapping; | |
235 | int maptype=vi.map_type[mapnum]; | |
236 | mode[i]=FuncMapping.mapping_P[maptype].look(this,vi.mode_param[i], | |
237 | vi.map_param[mapnum]); | |
238 | } | |
239 | return(0); | |
240 | } | |
241 | ||
242 | public int synthesis_init(Info vi){ | |
243 | init(vi, false); | |
244 | // Adjust centerW to allow an easier mechanism for determining output | |
245 | pcm_returned=centerW; | |
246 | centerW-= vi.blocksizes[W]/4+vi.blocksizes[lW]/4; | |
247 | granulepos=-1; | |
248 | sequence=-1; | |
249 | return(0); | |
250 | } | |
251 | ||
252 | DspState(Info vi){ | |
253 | this(); | |
254 | init(vi, false); | |
255 | // Adjust centerW to allow an easier mechanism for determining output | |
256 | pcm_returned=centerW; | |
257 | centerW-= vi.blocksizes[W]/4+vi.blocksizes[lW]/4; | |
258 | granulepos=-1; | |
259 | sequence=-1; | |
260 | } | |
261 | ||
262 | // Unike in analysis, the window is only partially applied for each | |
263 | // block. The time domain envelope is not yet handled at the point of | |
264 | // calling (as it relies on the previous block). | |
265 | ||
266 | public int synthesis_blockin(Block vb){ | |
267 | // Shift out any PCM/multipliers that we returned previously | |
268 | // centerW is currently the center of the last block added | |
269 | if(centerW>vi.blocksizes[1]/2 && pcm_returned>8192){ | |
270 | // don't shift too much; we need to have a minimum PCM buffer of | |
271 | // 1/2 long block | |
272 | ||
273 | int shiftPCM=centerW-vi.blocksizes[1]/2; | |
274 | shiftPCM=(pcm_returned<shiftPCM?pcm_returned:shiftPCM); | |
275 | ||
276 | pcm_current-=shiftPCM; | |
277 | centerW-=shiftPCM; | |
278 | pcm_returned-=shiftPCM; | |
279 | if(shiftPCM!=0){ | |
280 | for(int i=0;i<vi.channels;i++){ | |
281 | System.arraycopy(pcm[i], shiftPCM, pcm[i], 0, pcm_current); | |
282 | } | |
283 | } | |
284 | } | |
285 | ||
286 | lW=W; | |
287 | W=vb.W; | |
288 | nW=-1; | |
289 | ||
290 | glue_bits+=vb.glue_bits; | |
291 | time_bits+=vb.time_bits; | |
292 | floor_bits+=vb.floor_bits; | |
293 | res_bits+=vb.res_bits; | |
294 | ||
295 | if(sequence+1 != vb.sequence)granulepos=-1; // out of sequence; lose count | |
296 | ||
297 | sequence=vb.sequence; | |
298 | ||
299 | { | |
300 | int sizeW=vi.blocksizes[W]; | |
301 | int _centerW=centerW+vi.blocksizes[lW]/4+sizeW/4; | |
302 | int beginW=_centerW-sizeW/2; | |
303 | int endW=beginW+sizeW; | |
304 | int beginSl=0; | |
305 | int endSl=0; | |
306 | ||
307 | // Do we have enough PCM/mult storage for the block? | |
308 | if(endW>pcm_storage){ | |
309 | // expand the storage | |
310 | pcm_storage=endW+vi.blocksizes[1]; | |
311 | for(int i=0;i<vi.channels;i++){ | |
312 | float[] foo=new float[pcm_storage]; | |
313 | System.arraycopy(pcm[i], 0, foo, 0, pcm[i].length); | |
314 | pcm[i]=foo; | |
315 | } | |
316 | } | |
317 | ||
318 | // overlap/add PCM | |
319 | switch(W){ | |
320 | case 0: | |
321 | beginSl=0; | |
322 | endSl=vi.blocksizes[0]/2; | |
323 | break; | |
324 | case 1: | |
325 | beginSl=vi.blocksizes[1]/4-vi.blocksizes[lW]/4; | |
326 | endSl=beginSl+vi.blocksizes[lW]/2; | |
327 | break; | |
328 | } | |
329 | ||
330 | for(int j=0;j<vi.channels;j++){ | |
331 | int _pcm=beginW; | |
332 | // the overlap/add section | |
333 | int i=0; | |
334 | for(i=beginSl;i<endSl;i++){ | |
335 | pcm[j][_pcm+i]+=vb.pcm[j][i]; | |
336 | } | |
337 | // the remaining section | |
338 | for(;i<sizeW;i++){ | |
339 | pcm[j][_pcm+i]=vb.pcm[j][i]; | |
340 | } | |
341 | } | |
342 | ||
343 | // track the frame number... This is for convenience, but also | |
344 | // making sure our last packet doesn't end with added padding. If | |
345 | // the last packet is partial, the number of samples we'll have to | |
346 | // return will be past the vb->granulepos. | |
347 | // | |
348 | // This is not foolproof! It will be confused if we begin | |
349 | // decoding at the last page after a seek or hole. In that case, | |
350 | // we don't have a starting point to judge where the last frame | |
351 | // is. For this reason, vorbisfile will always try to make sure | |
352 | // it reads the last two marked pages in proper sequence | |
353 | ||
354 | if(granulepos==-1){ | |
355 | granulepos=vb.granulepos; | |
356 | } | |
357 | else{ | |
358 | granulepos+=(_centerW-centerW); | |
359 | if(vb.granulepos!=-1 && granulepos!=vb.granulepos){ | |
360 | if(granulepos>vb.granulepos && vb.eofflag!=0){ | |
361 | // partial last frame. Strip the padding off | |
362 | _centerW-=(granulepos-vb.granulepos); | |
363 | }// else{ Shouldn't happen *unless* the bitstream is out of | |
364 | // spec. Either way, believe the bitstream } | |
365 | granulepos=vb.granulepos; | |
366 | } | |
367 | } | |
368 | ||
369 | // Update, cleanup | |
370 | ||
371 | centerW=_centerW; | |
372 | pcm_current=endW; | |
373 | if(vb.eofflag!=0)eofflag=1; | |
374 | } | |
375 | return(0); | |
376 | } | |
377 | ||
378 | // pcm==NULL indicates we just want the pending samples, no more | |
379 | public int synthesis_pcmout(float[][][] _pcm, int[] index){ | |
380 | if(pcm_returned<centerW){ | |
381 | if(_pcm!=null){ | |
382 | for(int i=0;i<vi.channels;i++){ | |
383 | // pcmret[i]=pcm[i]+v.pcm_returned; | |
384 | //!!!!!!!! | |
385 | index[i]=pcm_returned; | |
386 | } | |
387 | _pcm[0]=pcm; | |
388 | } | |
389 | return(centerW-pcm_returned); | |
390 | } | |
391 | return(0); | |
392 | } | |
393 | ||
394 | public int synthesis_read(int bytes){ | |
395 | if(bytes!=0 && pcm_returned+bytes>centerW)return(-1); | |
396 | pcm_returned+=bytes; | |
397 | return(0); | |
398 | } | |
399 | ||
400 | public void clear(){ | |
401 | /* | |
402 | if(window[0][0][0]!=0){ | |
403 | for(i=0;i<VI_WINDOWB;i++) | |
404 | if(v->window[0][0][0][i])free(v->window[0][0][0][i]); | |
405 | free(v->window[0][0][0]); | |
406 | ||
407 | for(j=0;j<2;j++) | |
408 | for(k=0;k<2;k++){ | |
409 | for(i=0;i<VI_WINDOWB;i++) | |
410 | if(v->window[1][j][k][i])free(v->window[1][j][k][i]); | |
411 | free(v->window[1][j][k]); | |
412 | } | |
413 | } | |
414 | ||
415 | if(v->pcm){ | |
416 | for(i=0;i<vi->channels;i++) | |
417 | if(v->pcm[i])free(v->pcm[i]); | |
418 | free(v->pcm); | |
419 | if(v->pcmret)free(v->pcmret); | |
420 | } | |
421 | if(v->multipliers)free(v->multipliers); | |
422 | ||
423 | _ve_envelope_clear(&v->ve); | |
424 | if(v->transform[0]){ | |
425 | mdct_clear(v->transform[0][0]); | |
426 | free(v->transform[0][0]); | |
427 | free(v->transform[0]); | |
428 | } | |
429 | if(v->transform[1]){ | |
430 | mdct_clear(v->transform[1][0]); | |
431 | free(v->transform[1][0]); | |
432 | free(v->transform[1]); | |
433 | } | |
434 | ||
435 | // free mode lookups; these are actually vorbis_look_mapping structs | |
436 | if(vi){ | |
437 | for(i=0;i<vi->modes;i++){ | |
438 | int mapnum=vi->mode_param[i]->mapping; | |
439 | int maptype=vi->map_type[mapnum]; | |
440 | _mapping_P[maptype]->free_look(v->mode[i]); | |
441 | } | |
442 | // free codebooks | |
443 | for(i=0;i<vi->books;i++) | |
444 | vorbis_book_clear(v->fullbooks+i); | |
445 | } | |
446 | ||
447 | if(v->mode)free(v->mode); | |
448 | if(v->fullbooks)free(v->fullbooks); | |
449 | ||
450 | // free header, header1, header2 | |
451 | if(v->header)free(v->header); | |
452 | if(v->header1)free(v->header1); | |
453 | if(v->header2)free(v->header2); | |
454 | ||
455 | memset(v,0,sizeof(vorbis_dsp_state)); | |
456 | } | |
457 | */ | |
458 | } | |
459 | } |