001/* JOrbis
002 * Copyright (C) 2000 ymnk, JCraft,Inc.
003 *  
004 * Written by: 2000 ymnk<ymnk@jcaft.com>
005 *   
006 * Many thanks to 
007 *   Monty <monty@xiph.org> and 
008 *   The XIPHOPHORUS Company http://www.xiph.org/ .
009 * JOrbis has been based on their awesome works, Vorbis codec.
010 *   
011 * This program is free software; you can redistribute it and/or
012 * modify it under the terms of the GNU Library General Public License
013 * as published by the Free Software Foundation; either version 2 of
014 * the License, or (at your option) any later version.
015   
016 * This program is distributed in the hope that it will be useful,
017 * but WITHOUT ANY WARRANTY; without even the implied warranty of
018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
019 * GNU Library General Public License for more details.
020 * 
021 * You should have received a copy of the GNU Library General Public
022 * License along with this program; if not, write to the Free Software
023 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
024 */
025
026package com.jcraft.jorbis;
027
028import com.jcraft.jogg.*;
029
030class Floor0 extends FuncFloor{
031
032  void pack(Object i, Buffer opb){
033    InfoFloor0 info=(InfoFloor0)i;
034    opb.write(info.order,8);
035    opb.write(info.rate,16);
036    opb.write(info.barkmap,16);
037    opb.write(info.ampbits,6);
038    opb.write(info.ampdB,8);
039    opb.write(info.numbooks-1,4);
040    for(int j=0;j<info.numbooks;j++)
041      opb.write(info.books[j],8);
042  }
043
044  Object unpack(Info vi , Buffer opb){
045    InfoFloor0 info=new InfoFloor0();
046    info.order=opb.read(8);
047    info.rate=opb.read(16);
048    info.barkmap=opb.read(16);
049    info.ampbits=opb.read(6);
050    info.ampdB=opb.read(8);
051    info.numbooks=opb.read(4)+1;
052  
053    if((info.order<1)||
054       (info.rate<1)||
055       (info.barkmap<1)||
056       (info.numbooks<1)){
057      //free_info(info);
058      return(null);
059    }
060
061    for(int j=0;j<info.numbooks;j++){
062      info.books[j]=opb.read(8);
063      if(info.books[j]<0 || info.books[j]>=vi.books){
064        //free_info(info);
065        return(null);
066      }
067    }
068    return(info);  
069//  err_out:
070//    free_info(info);
071//    return(NULL);
072  }
073  Object look(DspState vd, InfoMode mi, Object i){
074    float scale;
075    Info vi=vd.vi;
076    InfoFloor0 info=(InfoFloor0)i;
077    LookFloor0 look=new LookFloor0();
078    look.m=info.order;
079    look.n=vi.blocksizes[mi.blockflag]/2;
080    look.ln=info.barkmap;
081    look.vi=info;
082    look.lpclook.init(look.ln,look.m);
083
084    // we choose a scaling constant so that:
085    //  floor(bark(rate/2-1)*C)=mapped-1
086    // floor(bark(rate/2)*C)=mapped
087    scale=look.ln/toBARK((float)(info.rate/2.));
088
089    // the mapping from a linear scale to a smaller bark scale is
090    // straightforward.  We do *not* make sure that the linear mapping
091    // does not skip bark-scale bins; the decoder simply skips them and
092    // the encoder may do what it wishes in filling them.  They're
093    // necessary in some mapping combinations to keep the scale spacing
094    // accurate
095    look.linearmap=new int[look.n];
096    for(int j=0;j<look.n;j++){
097      int val=(int)Math.floor(toBARK((float)((info.rate/2.)/look.n*j)) 
098                              *scale); // bark numbers represent band edges
099      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
325class 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
337class LookFloor0{
338  int n;
339  int ln;
340  int m;
341  int[] linearmap;
342
343  InfoFloor0 vi;
344  Lpc lpclook=new Lpc();
345}
346
347class EchstateFloor0{
348  int[] codewords;
349  float[] curve;
350  long frameno;
351  long codes;
352}