/* -*-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.Buffer; 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; } }