/* -*-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 Floor0 extends FuncFloor{ void pack(Object i, Buffer opb){ InfoFloor0 info=(InfoFloor0)i; opb.write(info.order, 8); opb.write(info.rate, 16); opb.write(info.barkmap, 16); opb.write(info.ampbits, 6); opb.write(info.ampdB, 8); opb.write(info.numbooks-1, 4); for(int j=0; j<info.numbooks; j++) opb.write(info.books[j], 8); } Object unpack(Info vi, Buffer opb){ InfoFloor0 info=new InfoFloor0(); info.order=opb.read(8); info.rate=opb.read(16); info.barkmap=opb.read(16); info.ampbits=opb.read(6); info.ampdB=opb.read(8); info.numbooks=opb.read(4)+1; if((info.order<1)||(info.rate<1)||(info.barkmap<1)||(info.numbooks<1)){ return (null); } for(int j=0; j<info.numbooks; j++){ info.books[j]=opb.read(8); if(info.books[j]<0||info.books[j]>=vi.books){ return (null); } } return (info); } Object look(DspState vd, InfoMode mi, Object i){ float scale; Info vi=vd.vi; InfoFloor0 info=(InfoFloor0)i; LookFloor0 look=new LookFloor0(); look.m=info.order; look.n=vi.blocksizes[mi.blockflag]/2; look.ln=info.barkmap; look.vi=info; look.lpclook.init(look.ln, look.m); // we choose a scaling constant so that: scale=look.ln/toBARK((float)(info.rate/2.)); // the mapping from a linear scale to a smaller bark scale is // straightforward. We do *not* make sure that the linear mapping // does not skip bark-scale bins; the decoder simply skips them and // the encoder may do what it wishes in filling them. They're // necessary in some mapping combinations to keep the scale spacing // accurate look.linearmap=new int[look.n]; for(int j=0; j<look.n; j++){ int val=(int)Math.floor(toBARK((float)((info.rate/2.)/look.n*j))*scale); // bark numbers represent band edges if(val>=look.ln) val=look.ln; // guard against the approximation look.linearmap[j]=val; } return look; } static float toBARK(float f){ return (float)(13.1*Math.atan(.00074*(f))+2.24*Math.atan((f)*(f)*1.85e-8)+1e-4*(f)); } Object state(Object i){ EchstateFloor0 state=new EchstateFloor0(); InfoFloor0 info=(InfoFloor0)i; // a safe size if usually too big (dim==1) state.codewords=new int[info.order]; state.curve=new float[info.barkmap]; state.frameno=-1; return (state); } void free_info(Object i){ } void free_look(Object i){ } void free_state(Object vs){ } int forward(Block vb, Object i, float[] in, float[] out, Object vs){ return 0; } float[] lsp=null; int inverse(Block vb, Object i, float[] out){ //System.err.println("Floor0.inverse "+i.getClass()+"]"); LookFloor0 look=(LookFloor0)i; InfoFloor0 info=look.vi; int ampraw=vb.opb.read(info.ampbits); if(ampraw>0){ // also handles the -1 out of data case int maxval=(1<<info.ampbits)-1; float amp=(float)ampraw/maxval*info.ampdB; int booknum=vb.opb.read(Util.ilog(info.numbooks)); if(booknum!=-1&&booknum<info.numbooks){ synchronized(this){ if(lsp==null||lsp.length<look.m){ lsp=new float[look.m]; } else{ for(int j=0; j<look.m; j++) lsp[j]=0.f; } CodeBook b=vb.vd.fullbooks[info.books[booknum]]; float last=0.f; for(int j=0; j<look.m; j++) out[j]=0.0f; for(int j=0; j<look.m; j+=b.dim){ if(b.decodevs(lsp, j, vb.opb, 1, -1)==-1){ for(int k=0; k<look.n; k++) out[k]=0.0f; return (0); } } for(int j=0; j<look.m;){ for(int k=0; k<b.dim; k++, j++) lsp[j]+=last; last=lsp[j-1]; } // take the coefficients back to a spectral envelope curve Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m, amp, info.ampdB); return (1); } } } return (0); } Object inverse1(Block vb, Object i, Object memo){ LookFloor0 look=(LookFloor0)i; InfoFloor0 info=look.vi; float[] lsp=null; if(memo instanceof float[]){ lsp=(float[])memo; } int ampraw=vb.opb.read(info.ampbits); if(ampraw>0){ // also handles the -1 out of data case int maxval=(1<<info.ampbits)-1; float amp=(float)ampraw/maxval*info.ampdB; int booknum=vb.opb.read(Util.ilog(info.numbooks)); if(booknum!=-1&&booknum<info.numbooks){ CodeBook b=vb.vd.fullbooks[info.books[booknum]]; float last=0.f; if(lsp==null||lsp.length<look.m+1){ lsp=new float[look.m+1]; } else{ for(int j=0; j<lsp.length; j++) lsp[j]=0.f; } for(int j=0; j<look.m; j+=b.dim){ if(b.decodev_set(lsp, j, vb.opb, b.dim)==-1){ return (null); } } for(int j=0; j<look.m;){ for(int k=0; k<b.dim; k++, j++) lsp[j]+=last; last=lsp[j-1]; } lsp[look.m]=amp; return (lsp); } } return (null); } int inverse2(Block vb, Object i, Object memo, float[] out){ LookFloor0 look=(LookFloor0)i; InfoFloor0 info=look.vi; if(memo!=null){ float[] lsp=(float[])memo; float amp=lsp[look.m]; Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m, amp, info.ampdB); return (1); } for(int j=0; j<look.n; j++){ out[j]=0.f; } return (0); } static float fromdB(float x){ return (float)(Math.exp((x)*.11512925)); } static void lsp_to_lpc(float[] lsp, float[] lpc, int m){ int i, j, m2=m/2; float[] O=new float[m2]; float[] E=new float[m2]; float A; float[] Ae=new float[m2+1]; float[] Ao=new float[m2+1]; float B; float[] Be=new float[m2]; float[] Bo=new float[m2]; float temp; // even/odd roots setup for(i=0; i<m2; i++){ O[i]=(float)(-2.*Math.cos(lsp[i*2])); E[i]=(float)(-2.*Math.cos(lsp[i*2+1])); } // set up impulse response for(j=0; j<m2; j++){ Ae[j]=0.f; Ao[j]=1.f; Be[j]=0.f; Bo[j]=1.f; } Ao[j]=1.f; Ae[j]=1.f; // run impulse response for(i=1; i<m+1; i++){ A=B=0.f; for(j=0; j<m2; j++){ temp=O[j]*Ao[j]+Ae[j]; Ae[j]=Ao[j]; Ao[j]=A; A+=temp; temp=E[j]*Bo[j]+Be[j]; Be[j]=Bo[j]; Bo[j]=B; B+=temp; } lpc[i-1]=(A+Ao[j]+B-Ae[j])/2; Ao[j]=A; Ae[j]=B; } } static void lpc_to_curve(float[] curve, float[] lpc, float amp, LookFloor0 l, String name, int frameno){ // l->m+1 must be less than l->ln, but guard in case we get a bad stream float[] lcurve=new float[Math.max(l.ln*2, l.m*2+2)]; if(amp==0){ for(int j=0; j<l.n; j++) curve[j]=0.0f; return; } l.lpclook.lpc_to_curve(lcurve, lpc, amp); for(int i=0; i<l.n; i++) curve[i]=lcurve[l.linearmap[i]]; } class InfoFloor0{ int order; int rate; int barkmap; int ampbits; int ampdB; int numbooks; // <= 16 int[] books=new int[16]; } class LookFloor0{ int n; int ln; int m; int[] linearmap; InfoFloor0 vi; Lpc lpclook=new Lpc(); } class EchstateFloor0{ int[] codewords; float[] curve; long frameno; long codes; } }