]>
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 Mapping0 extends FuncMapping{ | |
31 | static int seq=0; | |
32 | void free_info(Object imap){}; | |
33 | void free_look(Object imap){ | |
34 | /* | |
35 | LookMapping0 l=(LookMapping0)imap; | |
36 | InfoMapping0 info=l.map; | |
37 | if(l!=null){ | |
38 | for(int i=0;i<l.map.submaps;i++){ | |
39 | l.time_func[i].free_look(l.time_look[i]); | |
40 | l.floor_func[i].free_look(l.floor_look[i]); | |
41 | l.residue_func[i].free_look(l.residue_look[i]); | |
42 | if(l.psy_look!=null)l.psy_look[i].clear(); | |
43 | } | |
44 | } | |
45 | ||
46 | if(l.floor_state!=null){ | |
47 | for(int i=0;i<l.ch;i++) | |
48 | l.floor_func[info.chmuxlist[i]].free_state(l.floor_state[i]); | |
49 | //free(l.floor_state); | |
50 | } | |
51 | ||
52 | if(l.decay!=null){ | |
53 | for(int i=0;i<l.ch;i++){ | |
54 | //if(l.decay[i])free(l->decay[i]); | |
55 | l.decay[i]=null; | |
56 | } | |
57 | //free(l->decay); | |
58 | l.decay=null; | |
59 | } | |
60 | //free(l->time_func); | |
61 | //free(l->floor_func); | |
62 | //free(l->residue_func); | |
63 | //free(l->time_look); | |
64 | //free(l->floor_look); | |
65 | //free(l->residue_look); | |
66 | //f(l->psy_look)free(l->psy_look); | |
67 | l.time_func=null; | |
68 | l.floor_func=null; | |
69 | l.residue_func=null; | |
70 | l.time_look=null; | |
71 | l.floor_look=null; | |
72 | l.residue_look=null; | |
73 | //memset(l,0,sizeof(vorbis_look_mapping0)); | |
74 | //free(l); | |
75 | */ | |
76 | } | |
77 | ||
78 | Object look(DspState vd, InfoMode vm, Object m){ | |
79 | //System.err.println("Mapping0.look"); | |
80 | Info vi=vd.vi; | |
81 | LookMapping0 look=new LookMapping0(); | |
82 | InfoMapping0 info=look.map=(InfoMapping0)m; | |
83 | look.mode=vm; | |
84 | ||
85 | look.time_look=new Object[info.submaps]; | |
86 | look.floor_look=new Object[info.submaps]; | |
87 | look.residue_look=new Object[info.submaps]; | |
88 | ||
89 | /* | |
90 | if(vd.analysisp!=0){ | |
91 | look.floor_state=new Object[vi.channels]; | |
92 | } | |
93 | if(vi.psys!=0){ | |
94 | look.psy_look=new PsyLook[info.submaps]; | |
95 | for(int i=0; i<info.submaps; i++){ look.psy_look[i]=new PsyLook(); } | |
96 | } | |
97 | */ | |
98 | ||
99 | look.time_func=new FuncTime[info.submaps]; | |
100 | look.floor_func=new FuncFloor[info.submaps]; | |
101 | look.residue_func=new FuncResidue[info.submaps]; | |
102 | ||
103 | for(int i=0;i<info.submaps;i++){ | |
104 | int timenum=info.timesubmap[i]; | |
105 | int floornum=info.floorsubmap[i]; | |
106 | int resnum=info.residuesubmap[i]; | |
107 | ||
108 | look.time_func[i]=FuncTime.time_P[vi.time_type[timenum]]; | |
109 | look.time_look[i]=look.time_func[i].look(vd,vm,vi.time_param[timenum]); | |
110 | look.floor_func[i]=FuncFloor.floor_P[vi.floor_type[floornum]]; | |
111 | look.floor_look[i]=look.floor_func[i]. | |
112 | look(vd,vm,vi.floor_param[floornum]); | |
113 | look.residue_func[i]=FuncResidue.residue_P[vi.residue_type[resnum]]; | |
114 | look.residue_look[i]=look.residue_func[i]. | |
115 | look(vd,vm,vi.residue_param[resnum]); | |
116 | ||
117 | /* | |
118 | if(vi.psys!=0 && vd.analysisp!=0){ | |
119 | int psynum=info.psysubmap[i]; | |
120 | look.psy_look[i].init(vi.psy_param[psynum], | |
121 | vi.blocksizes[vm.blockflag]/2,vi.rate); | |
122 | } | |
123 | */ | |
124 | } | |
125 | ||
126 | if(vi.psys!=0 && vd.analysisp!=0){ | |
127 | /* | |
128 | if(info->psy[0] != info->psy[1]){ | |
129 | ||
130 | int psynum=info->psy[0]; | |
131 | look->psy_look[0]=_ogg_calloc(1,sizeof(vorbis_look_psy)); | |
132 | _vp_psy_init(look->psy_look[0],ci->psy_param[psynum], | |
133 | ci->psy_g_param, | |
134 | ci->blocksizes[vm->blockflag]/2,vi->rate); | |
135 | ||
136 | psynum=info->psy[1]; | |
137 | look->psy_look[1]=_ogg_calloc(1,sizeof(vorbis_look_psy)); | |
138 | _vp_psy_init(look->psy_look[1],ci->psy_param[psynum], | |
139 | ci->psy_g_param, | |
140 | ci->blocksizes[vm->blockflag]/2,vi->rate); | |
141 | }else{ | |
142 | ||
143 | int psynum=info->psy[0]; | |
144 | look->psy_look[0]=_ogg_calloc(1,sizeof(vorbis_look_psy)); | |
145 | look->psy_look[1]=look->psy_look[0]; | |
146 | _vp_psy_init(look->psy_look[0],ci->psy_param[psynum], | |
147 | ci->psy_g_param, | |
148 | ci->blocksizes[vm->blockflag]/2,vi->rate); | |
149 | ||
150 | } | |
151 | */ | |
152 | } | |
153 | ||
154 | look.ch=vi.channels; | |
155 | // if(vd->analysisp)drft_init(&look->fft_look,ci->blocksizes[vm->blockflag]); | |
156 | ||
157 | return(look); | |
158 | //return null; | |
159 | } | |
160 | ||
161 | void pack(Info vi, Object imap, Buffer opb){ | |
162 | InfoMapping0 info=(InfoMapping0)imap; | |
163 | ||
164 | /* another 'we meant to do it this way' hack... up to beta 4, we | |
165 | packed 4 binary zeros here to signify one submapping in use. We | |
166 | now redefine that to mean four bitflags that indicate use of | |
167 | deeper features; bit0:submappings, bit1:coupling, | |
168 | bit2,3:reserved. This is backward compatable with all actual uses | |
169 | of the beta code. */ | |
170 | ||
171 | if(info.submaps>1){ | |
172 | opb.write(1,1); | |
173 | opb.write(info.submaps-1,4); | |
174 | } | |
175 | else{ | |
176 | opb.write(0,1); | |
177 | } | |
178 | ||
179 | if(info.coupling_steps>0){ | |
180 | opb.write(1,1); | |
181 | opb.write(info.coupling_steps-1,8); | |
182 | for(int i=0;i<info.coupling_steps;i++){ | |
183 | opb.write(info.coupling_mag[i],ilog2(vi.channels)); | |
184 | opb.write(info.coupling_ang[i],ilog2(vi.channels)); | |
185 | } | |
186 | } | |
187 | else{ | |
188 | opb.write(0,1); | |
189 | } | |
190 | ||
191 | opb.write(0,2); /* 2,3:reserved */ | |
192 | ||
193 | /* we don't write the channel submappings if we only have one... */ | |
194 | if(info.submaps>1){ | |
195 | for(int i=0;i<vi.channels;i++) | |
196 | opb.write(info.chmuxlist[i],4); | |
197 | } | |
198 | for(int i=0;i<info.submaps;i++){ | |
199 | opb.write(info.timesubmap[i],8); | |
200 | opb.write(info.floorsubmap[i],8); | |
201 | opb.write(info.residuesubmap[i],8); | |
202 | } | |
203 | } | |
204 | ||
205 | // also responsible for range checking | |
206 | Object unpack(Info vi, Buffer opb){ | |
207 | InfoMapping0 info=new InfoMapping0(); | |
208 | ||
209 | // !!!! | |
210 | if(opb.read(1)!=0){ | |
211 | info.submaps=opb.read(4)+1; | |
212 | } | |
213 | else{ | |
214 | info.submaps=1; | |
215 | } | |
216 | ||
217 | if(opb.read(1)!=0){ | |
218 | info.coupling_steps=opb.read(8)+1; | |
219 | ||
220 | for(int i=0;i<info.coupling_steps;i++){ | |
221 | int testM=info.coupling_mag[i]=opb.read(ilog2(vi.channels)); | |
222 | int testA=info.coupling_ang[i]=opb.read(ilog2(vi.channels)); | |
223 | ||
224 | if(testM<0 || | |
225 | testA<0 || | |
226 | testM==testA || | |
227 | testM>=vi.channels || | |
228 | testA>=vi.channels){ | |
229 | //goto err_out; | |
230 | info.free(); | |
231 | return(null); | |
232 | } | |
233 | } | |
234 | } | |
235 | ||
236 | if(opb.read(2)>0){ /* 2,3:reserved */ | |
237 | //goto err_out; | |
238 | info.free(); | |
239 | return(null); | |
240 | } | |
241 | ||
242 | if(info.submaps>1){ | |
243 | for(int i=0;i<vi.channels;i++){ | |
244 | info.chmuxlist[i]=opb.read(4); | |
245 | if(info.chmuxlist[i]>=info.submaps){ | |
246 | //goto err_out; | |
247 | info.free(); | |
248 | return(null); | |
249 | } | |
250 | } | |
251 | } | |
252 | ||
253 | for(int i=0;i<info.submaps;i++){ | |
254 | info.timesubmap[i]=opb.read(8); | |
255 | if(info.timesubmap[i]>=vi.times){ | |
256 | //goto err_out; | |
257 | info.free(); | |
258 | return(null); | |
259 | } | |
260 | info.floorsubmap[i]=opb.read(8); | |
261 | if(info.floorsubmap[i]>=vi.floors){ | |
262 | //goto err_out; | |
263 | info.free(); | |
264 | return(null); | |
265 | } | |
266 | info.residuesubmap[i]=opb.read(8); | |
267 | if(info.residuesubmap[i]>=vi.residues){ | |
268 | //goto err_out; | |
269 | info.free(); | |
270 | return(null); | |
271 | } | |
272 | } | |
273 | return info; | |
274 | //err_out: | |
275 | //free_info(info); | |
276 | //return(NULL); | |
277 | } | |
278 | ||
279 | /* | |
280 | // no time mapping implementation for now | |
281 | static int seq=0; | |
282 | int forward(Block vb, Object l){ | |
283 | DspState vd=vb.vd; | |
284 | Info vi=vd.vi; | |
285 | LookMapping0 look=(LookMapping0)l; | |
286 | InfoMapping0 info=look.map; | |
287 | InfoMode mode=look.mode; | |
288 | int n=vb.pcmend; | |
289 | float[] window=vd.window[vb.W][vb.lW][vb.nW][mode.windowtype]; | |
290 | ||
291 | float[][] pcmbundle=new float[vi.channles][]; | |
292 | int[] nonzero=new int[vi.channels]; | |
293 | ||
294 | // time domain pre-window: NONE IMPLEMENTED | |
295 | ||
296 | // window the PCM data: takes PCM vector, vb; modifies PCM vector | |
297 | ||
298 | for(int i=0;i<vi.channels;i++){ | |
299 | float[] pcm=vb.pcm[i]; | |
300 | for(int j=0;j<n;j++) | |
301 | pcm[j]*=window[j]; | |
302 | } | |
303 | ||
304 | // time-domain post-window: NONE IMPLEMENTED | |
305 | ||
306 | // transform the PCM data; takes PCM vector, vb; modifies PCM vector | |
307 | // only MDCT right now.... | |
308 | for(int i=0;i<vi.channels;i++){ | |
309 | float[] pcm=vb.pcm[i]; | |
310 | mdct_forward(vd.transform[vb.W][0],pcm,pcm); | |
311 | } | |
312 | ||
313 | { | |
314 | float[] floor=_vorbis_block_alloc(vb,n*sizeof(float)/2); | |
315 | ||
316 | for(int i=0;i<vi.channels;i++){ | |
317 | float[] pcm=vb.pcm[i]; | |
318 | float[] decay=look.decay[i]; | |
319 | int submap=info.chmuxlist[i]; | |
320 | ||
321 | // if some other mode/mapping was called last frame, our decay | |
322 | // accumulator is out of date. Clear it. | |
323 | //if(look.lastframe+1 != vb->sequence) | |
324 | // memset(decay,0,n*sizeof(float)/2); | |
325 | ||
326 | // perform psychoacoustics; do masking | |
327 | _vp_compute_mask(look.psy_look[submap],pcm,floor,decay); | |
328 | ||
329 | _analysis_output("mdct",seq,pcm,n/2,0,1); | |
330 | _analysis_output("lmdct",seq,pcm,n/2,0,0); | |
331 | _analysis_output("prefloor",seq,floor,n/2,0,1); | |
332 | ||
333 | // perform floor encoding | |
334 | nonzero[i]=look.floor_func[submap]. | |
335 | forward(vb,look.floor_look[submap],floor,floor,look.floor_state[i]); | |
336 | ||
337 | _analysis_output("floor",seq,floor,n/2,0,1); | |
338 | ||
339 | // apply the floor, do optional noise levelling | |
340 | _vp_apply_floor(look->psy_look+submap,pcm,floor); | |
341 | ||
342 | _analysis_output("res",seq++,pcm,n/2,0,0); | |
343 | } | |
344 | ||
345 | // perform residue encoding with residue mapping; this is | |
346 | // multiplexed. All the channels belonging to one submap are | |
347 | // encoded (values interleaved), then the next submap, etc | |
348 | ||
349 | for(int i=0;i<info.submaps;i++){ | |
350 | int ch_in_bundle=0; | |
351 | for(int j=0;j<vi.channels;j++){ | |
352 | if(info.chmuxlist[j]==i && nonzero[j]==1){ | |
353 | pcmbundle[ch_in_bundle++]=vb.pcm[j]; | |
354 | } | |
355 | } | |
356 | look.residue_func[i].forward(vb,look.residue_look[i], pcmbundle,ch_in_bundle); | |
357 | } | |
358 | } | |
359 | look.lastframe=vb.sequence; | |
360 | return(0); | |
361 | } | |
362 | */ | |
363 | ||
364 | float[][] pcmbundle=null; | |
365 | int[] zerobundle=null; | |
366 | int[] nonzero=null; | |
367 | Object[] floormemo=null; | |
368 | ||
369 | synchronized int inverse(Block vb, Object l){ | |
370 | //System.err.println("Mapping0.inverse"); | |
371 | DspState vd=vb.vd; | |
372 | Info vi=vd.vi; | |
373 | LookMapping0 look=(LookMapping0)l; | |
374 | InfoMapping0 info=look.map; | |
375 | InfoMode mode=look.mode; | |
376 | int n=vb.pcmend=vi.blocksizes[vb.W]; | |
377 | ||
378 | float[] window=vd.window[vb.W][vb.lW][vb.nW][mode.windowtype]; | |
379 | // float[][] pcmbundle=new float[vi.channels][]; | |
380 | // int[] nonzero=new int[vi.channels]; | |
381 | if(pcmbundle==null || pcmbundle.length<vi.channels){ | |
382 | pcmbundle=new float[vi.channels][]; | |
383 | nonzero=new int[vi.channels]; | |
384 | zerobundle=new int[vi.channels]; | |
385 | floormemo=new Object[vi.channels]; | |
386 | } | |
387 | ||
388 | // time domain information decode (note that applying the | |
389 | // information would have to happen later; we'll probably add a | |
390 | // function entry to the harness for that later | |
391 | // NOT IMPLEMENTED | |
392 | ||
393 | // recover the spectral envelope; store it in the PCM vector for now | |
394 | for(int i=0;i<vi.channels;i++){ | |
395 | float[] pcm=vb.pcm[i]; | |
396 | int submap=info.chmuxlist[i]; | |
397 | ||
398 | floormemo[i]=look.floor_func[submap].inverse1(vb,look. | |
399 | floor_look[submap], | |
400 | floormemo[i] | |
401 | ); | |
402 | if(floormemo[i]!=null){ nonzero[i]=1; } | |
403 | else{ nonzero[i]=0; } | |
404 | for(int j=0; j<n/2; j++){ | |
405 | pcm[j]=0; | |
406 | } | |
407 | ||
408 | //_analysis_output("ifloor",seq+i,pcm,n/2,0,1); | |
409 | } | |
410 | ||
411 | for(int i=0; i<info.coupling_steps; i++){ | |
412 | if(nonzero[info.coupling_mag[i]]!=0 || | |
413 | nonzero[info.coupling_ang[i]]!=0){ | |
414 | nonzero[info.coupling_mag[i]]=1; | |
415 | nonzero[info.coupling_ang[i]]=1; | |
416 | } | |
417 | } | |
418 | ||
419 | // recover the residue, apply directly to the spectral envelope | |
420 | ||
421 | for(int i=0;i<info.submaps;i++){ | |
422 | int ch_in_bundle=0; | |
423 | for(int j=0;j<vi.channels;j++){ | |
424 | if(info.chmuxlist[j]==i){ | |
425 | if(nonzero[j]!=0){ | |
426 | zerobundle[ch_in_bundle]=1; | |
427 | } | |
428 | else{ | |
429 | zerobundle[ch_in_bundle]=0; | |
430 | } | |
431 | pcmbundle[ch_in_bundle++]=vb.pcm[j]; | |
432 | } | |
433 | } | |
434 | ||
435 | look.residue_func[i].inverse(vb,look.residue_look[i], | |
436 | pcmbundle,zerobundle,ch_in_bundle); | |
437 | } | |
438 | ||
439 | ||
440 | for(int i=info.coupling_steps-1;i>=0;i--){ | |
441 | float[] pcmM=vb.pcm[info.coupling_mag[i]]; | |
442 | float[] pcmA=vb.pcm[info.coupling_ang[i]]; | |
443 | ||
444 | for(int j=0;j<n/2;j++){ | |
445 | float mag=pcmM[j]; | |
446 | float ang=pcmA[j]; | |
447 | ||
448 | if(mag>0){ | |
449 | if(ang>0){ | |
450 | pcmM[j]=mag; | |
451 | pcmA[j]=mag-ang; | |
452 | } | |
453 | else{ | |
454 | pcmA[j]=mag; | |
455 | pcmM[j]=mag+ang; | |
456 | } | |
457 | } | |
458 | else{ | |
459 | if(ang>0){ | |
460 | pcmM[j]=mag; | |
461 | pcmA[j]=mag+ang; | |
462 | } | |
463 | else{ | |
464 | pcmA[j]=mag; | |
465 | pcmM[j]=mag-ang; | |
466 | } | |
467 | } | |
468 | } | |
469 | } | |
470 | ||
471 | // /* compute and apply spectral envelope */ | |
472 | ||
473 | for(int i=0;i<vi.channels;i++){ | |
474 | float[] pcm=vb.pcm[i]; | |
475 | int submap=info.chmuxlist[i]; | |
476 | look.floor_func[submap].inverse2(vb,look.floor_look[submap],floormemo[i],pcm); | |
477 | } | |
478 | ||
479 | // transform the PCM data; takes PCM vector, vb; modifies PCM vector | |
480 | // only MDCT right now.... | |
481 | ||
482 | for(int i=0;i<vi.channels;i++){ | |
483 | float[] pcm=vb.pcm[i]; | |
484 | //_analysis_output("out",seq+i,pcm,n/2,0,0); | |
485 | ((Mdct)vd.transform[vb.W][0]).backward(pcm,pcm); | |
486 | } | |
487 | ||
488 | // now apply the decoded pre-window time information | |
489 | // NOT IMPLEMENTED | |
490 | ||
491 | // window the data | |
492 | for(int i=0;i<vi.channels;i++){ | |
493 | float[] pcm=vb.pcm[i]; | |
494 | if(nonzero[i]!=0){ | |
495 | for(int j=0;j<n;j++){ | |
496 | pcm[j]*=window[j]; | |
497 | } | |
498 | } | |
499 | else{ | |
500 | for(int j=0;j<n;j++){ | |
501 | pcm[j]=0.f; | |
502 | } | |
503 | } | |
504 | //_analysis_output("final",seq++,pcm,n,0,0); | |
505 | } | |
506 | ||
507 | // now apply the decoded post-window time information | |
508 | // NOT IMPLEMENTED | |
509 | // all done! | |
510 | return(0); | |
511 | } | |
512 | ||
513 | ||
514 | private static int ilog2(int v){ | |
515 | int ret=0; | |
516 | while(v>1){ | |
517 | ret++; | |
518 | v>>>=1; | |
519 | } | |
520 | return(ret); | |
521 | } | |
522 | } | |
523 | ||
524 | class InfoMapping0{ | |
525 | int submaps; // <= 16 | |
526 | int[] chmuxlist=new int[256]; // up to 256 channels in a Vorbis stream | |
527 | ||
528 | int[] timesubmap=new int[16]; // [mux] | |
529 | int[] floorsubmap=new int[16]; // [mux] submap to floors | |
530 | int[] residuesubmap=new int[16];// [mux] submap to residue | |
531 | int[] psysubmap=new int[16]; // [mux]; encode only | |
532 | ||
533 | int coupling_steps; | |
534 | int[] coupling_mag=new int[256]; | |
535 | int[] coupling_ang=new int[256]; | |
536 | ||
537 | void free(){ | |
538 | chmuxlist=null; | |
539 | timesubmap=null; | |
540 | floorsubmap=null; | |
541 | residuesubmap=null; | |
542 | psysubmap=null; | |
543 | ||
544 | coupling_mag=null; | |
545 | coupling_ang=null; | |
546 | } | |
547 | } | |
548 | ||
549 | class LookMapping0{ | |
550 | InfoMode mode; | |
551 | InfoMapping0 map; | |
552 | Object[] time_look; | |
553 | Object[] floor_look; | |
554 | Object[] floor_state; | |
555 | Object[] residue_look; | |
556 | PsyLook[] psy_look; | |
557 | ||
558 | FuncTime[] time_func; | |
559 | FuncFloor[] floor_func; | |
560 | FuncResidue[] residue_func; | |
561 | ||
562 | int ch; | |
563 | float[][] decay; | |
564 | int lastframe; // if a different mode is called, we need to | |
565 | // invalidate decay and floor state | |
566 | } |