/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* JOrbis * Copyright (C) 2000 ymnk, JCraft,Inc. * * Written by: 2000 ymnk<ymnk@jcraft.com> * * Many thanks to * Monty <monty@xiph.org> and * The XIPHOPHORUS Company http://www.xiph.org/ . * JOrbis has been based on their awesome works, Vorbis codec. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package com.jcraft.jorbis; import com.jcraft.jogg.*; class Residue0 extends FuncResidue{ void pack(Object vr, Buffer opb){ InfoResidue0 info=(InfoResidue0)vr; int acc=0; opb.write(info.begin, 24); opb.write(info.end, 24); opb.write(info.grouping-1, 24); /* residue vectors to group and code with a partitioned book */ opb.write(info.partitions-1, 6); /* possible partition choices */ opb.write(info.groupbook, 8); /* group huffman book */ /* secondstages is a bitmask; as encoding progresses pass by pass, a bitmask of one indicates this partition class has bits to write this pass */ for(int j=0; j<info.partitions; j++){ int i=info.secondstages[j]; if(Util.ilog(i)>3){ /* yes, this is a minor hack due to not thinking ahead */ opb.write(i, 3); opb.write(1, 1); opb.write(i>>>3, 5); } else{ opb.write(i, 4); /* trailing zero */ } acc+=Util.icount(i); } for(int j=0; j<acc; j++){ opb.write(info.booklist[j], 8); } } Object unpack(Info vi, Buffer opb){ int acc=0; InfoResidue0 info=new InfoResidue0(); info.begin=opb.read(24); info.end=opb.read(24); info.grouping=opb.read(24)+1; info.partitions=opb.read(6)+1; info.groupbook=opb.read(8); for(int j=0; j<info.partitions; j++){ int cascade=opb.read(3); if(opb.read(1)!=0){ cascade|=(opb.read(5)<<3); } info.secondstages[j]=cascade; acc+=Util.icount(cascade); } for(int j=0; j<acc; j++){ info.booklist[j]=opb.read(8); } if(info.groupbook>=vi.books){ free_info(info); return (null); } for(int j=0; j<acc; j++){ if(info.booklist[j]>=vi.books){ free_info(info); return (null); } } return (info); } Object look(DspState vd, InfoMode vm, Object vr){ InfoResidue0 info=(InfoResidue0)vr; LookResidue0 look=new LookResidue0(); int acc=0; int dim; int maxstage=0; look.info=info; look.map=vm.mapping; look.parts=info.partitions; look.fullbooks=vd.fullbooks; look.phrasebook=vd.fullbooks[info.groupbook]; dim=look.phrasebook.dim; look.partbooks=new int[look.parts][]; for(int j=0; j<look.parts; j++){ int i=info.secondstages[j]; int stages=Util.ilog(i); if(stages!=0){ if(stages>maxstage) maxstage=stages; look.partbooks[j]=new int[stages]; for(int k=0; k<stages; k++){ if((i&(1<<k))!=0){ look.partbooks[j][k]=info.booklist[acc++]; } } } } look.partvals=(int)Math.rint(Math.pow(look.parts, dim)); look.stages=maxstage; look.decodemap=new int[look.partvals][]; for(int j=0; j<look.partvals; j++){ int val=j; int mult=look.partvals/look.parts; look.decodemap[j]=new int[dim]; for(int k=0; k<dim; k++){ int deco=val/mult; val-=deco*mult; mult/=look.parts; look.decodemap[j][k]=deco; } } return (look); } void free_info(Object i){ } void free_look(Object i){ } private static int[][][] _01inverse_partword=new int[2][][]; // _01inverse is synchronized for // re-using partword synchronized static int _01inverse(Block vb, Object vl, float[][] in, int ch, int decodepart){ int i, j, k, l, s; LookResidue0 look=(LookResidue0)vl; InfoResidue0 info=look.info; // move all this setup out later int samples_per_partition=info.grouping; int partitions_per_word=look.phrasebook.dim; int n=info.end-info.begin; int partvals=n/samples_per_partition; int partwords=(partvals+partitions_per_word-1)/partitions_per_word; if(_01inverse_partword.length<ch){ _01inverse_partword=new int[ch][][]; } for(j=0; j<ch; j++){ if(_01inverse_partword[j]==null||_01inverse_partword[j].length<partwords){ _01inverse_partword[j]=new int[partwords][]; } } for(s=0; s<look.stages; s++){ // each loop decodes on partition codeword containing // partitions_pre_word partitions for(i=0, l=0; i<partvals; l++){ if(s==0){ // fetch the partition word for each channel for(j=0; j<ch; j++){ int temp=look.phrasebook.decode(vb.opb); if(temp==-1){ return (0); } _01inverse_partword[j][l]=look.decodemap[temp]; if(_01inverse_partword[j][l]==null){ return (0); } } } // now we decode residual values for the partitions for(k=0; k<partitions_per_word&&i<partvals; k++, i++) for(j=0; j<ch; j++){ int offset=info.begin+i*samples_per_partition; int index=_01inverse_partword[j][l][k]; if((info.secondstages[index]&(1<<s))!=0){ CodeBook stagebook=look.fullbooks[look.partbooks[index][s]]; if(stagebook!=null){ if(decodepart==0){ if(stagebook.decodevs_add(in[j], offset, vb.opb, samples_per_partition)==-1){ return (0); } } else if(decodepart==1){ if(stagebook.decodev_add(in[j], offset, vb.opb, samples_per_partition)==-1){ return (0); } } } } } } } return (0); } static int[][] _2inverse_partword=null; synchronized static int _2inverse(Block vb, Object vl, float[][] in, int ch){ int i, k, l, s; LookResidue0 look=(LookResidue0)vl; InfoResidue0 info=look.info; // move all this setup out later int samples_per_partition=info.grouping; int partitions_per_word=look.phrasebook.dim; int n=info.end-info.begin; int partvals=n/samples_per_partition; int partwords=(partvals+partitions_per_word-1)/partitions_per_word; if(_2inverse_partword==null||_2inverse_partword.length<partwords){ _2inverse_partword=new int[partwords][]; } for(s=0; s<look.stages; s++){ for(i=0, l=0; i<partvals; l++){ if(s==0){ // fetch the partition word for each channel int temp=look.phrasebook.decode(vb.opb); if(temp==-1){ return (0); } _2inverse_partword[l]=look.decodemap[temp]; if(_2inverse_partword[l]==null){ return (0); } } // now we decode residual values for the partitions for(k=0; k<partitions_per_word&&i<partvals; k++, i++){ int offset=info.begin+i*samples_per_partition; int index=_2inverse_partword[l][k]; if((info.secondstages[index]&(1<<s))!=0){ CodeBook stagebook=look.fullbooks[look.partbooks[index][s]]; if(stagebook!=null){ if(stagebook.decodevv_add(in, offset, ch, vb.opb, samples_per_partition)==-1){ return (0); } } } } } } return (0); } int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){ int used=0; for(int i=0; i<ch; i++){ if(nonzero[i]!=0){ in[used++]=in[i]; } } if(used!=0) return (_01inverse(vb, vl, in, used, 0)); else return (0); } class LookResidue0{ InfoResidue0 info; int map; int parts; int stages; CodeBook[] fullbooks; CodeBook phrasebook; int[][] partbooks; int partvals; int[][] decodemap; int postbits; int phrasebits; int frames; } class InfoResidue0{ // block-partitioned VQ coded straight residue int begin; int end; // first stage (lossless partitioning) int grouping; // group n vectors per partition int partitions; // possible codebooks for a partition int groupbook; // huffbook for partitioning int[] secondstages=new int[64]; // expanded out to pointers in lookup int[] booklist=new int[256]; // list of second stage books // encode-only heuristic settings float[] entmax=new float[64]; // book entropy threshholds float[] ampmax=new float[64]; // book amp threshholds int[] subgrp=new int[64]; // book heuristic subgroup size int[] blimit=new int[64]; // subgroup position limits } }