Spaces:
Build error
Build error
/* -*-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 StaticCodeBook { | |
int dim; // codebook dimensions (elements per vector) | |
int entries; // codebook entries | |
int[] lengthlist; // codeword lengths in bits | |
// mapping | |
int maptype; // 0=none | |
// 1=implicitly populated values from map column | |
// 2=listed arbitrary values | |
// The below does a linear, single monotonic sequence mapping. | |
int q_min; // packed 32 bit float; quant value 0 maps to minval | |
int q_delta; // packed 32 bit float; val 1 - val 0 == delta | |
int q_quant; // bits: 0 < quant <= 16 | |
int q_sequencep; // bitflag | |
// additional information for log (dB) mapping; the linear mapping | |
// is assumed to actually be values in dB. encodebias is used to | |
// assign an error weight to 0 dB. We have two additional flags: | |
// zeroflag indicates if entry zero is to represent -Inf dB; negflag | |
// indicates if we're to represent negative linear values in a | |
// mirror of the positive mapping. | |
int[] quantlist; // map == 1: (int)(entries/dim) element column map | |
// map == 2: list of dim*entries quantized entry vals | |
StaticCodeBook() { | |
} | |
int pack(Buffer opb) { | |
int i; | |
boolean ordered = false; | |
opb.write(0x564342, 24); | |
opb.write(dim, 16); | |
opb.write(entries, 24); | |
// pack the codewords. There are two packings; length ordered and | |
// length random. Decide between the two now. | |
for (i = 1; i < entries; i++) { | |
if (lengthlist[i] < lengthlist[i - 1]) | |
break; | |
} | |
if (i == entries) | |
ordered = true; | |
if (ordered) { | |
// length ordered. We only need to say how many codewords of | |
// each length. The actual codewords are generated | |
// deterministically | |
int count = 0; | |
opb.write(1, 1); // ordered | |
opb.write(lengthlist[0] - 1, 5); // 1 to 32 | |
for (i = 1; i < entries; i++) { | |
int _this = lengthlist[i]; | |
int _last = lengthlist[i - 1]; | |
if (_this > _last) { | |
for (int j = _last; j < _this; j++) { | |
opb.write(i - count, Util.ilog(entries - count)); | |
count = i; | |
} | |
} | |
} | |
opb.write(i - count, Util.ilog(entries - count)); | |
} else { | |
// length random. Again, we don't code the codeword itself, just | |
// the length. This time, though, we have to encode each length | |
opb.write(0, 1); // unordered | |
// algortihmic mapping has use for 'unused entries', which we tag | |
// here. The algorithmic mapping happens as usual, but the unused | |
// entry has no codeword. | |
for (i = 0; i < entries; i++) { | |
if (lengthlist[i] == 0) | |
break; | |
} | |
if (i == entries) { | |
opb.write(0, 1); // no unused entries | |
for (i = 0; i < entries; i++) { | |
opb.write(lengthlist[i] - 1, 5); | |
} | |
} else { | |
opb.write(1, 1); // we have unused entries; thus we tag | |
for (i = 0; i < entries; i++) { | |
if (lengthlist[i] == 0) { | |
opb.write(0, 1); | |
} else { | |
opb.write(1, 1); | |
opb.write(lengthlist[i] - 1, 5); | |
} | |
} | |
} | |
} | |
// is the entry number the desired return value, or do we have a | |
// mapping? If we have a mapping, what type? | |
opb.write(maptype, 4); | |
switch (maptype) { | |
case 0: | |
// no mapping | |
break; | |
case 1: | |
case 2: | |
// implicitly populated value mapping | |
// explicitly populated value mapping | |
if (quantlist == null) { | |
// no quantlist? error | |
return (-1); | |
} | |
// values that define the dequantization | |
opb.write(q_min, 32); | |
opb.write(q_delta, 32); | |
opb.write(q_quant - 1, 4); | |
opb.write(q_sequencep, 1); | |
{ | |
int quantvals = 0; | |
switch (maptype) { | |
case 1: | |
// a single column of (c->entries/c->dim) quantized values for | |
// building a full value list algorithmically (square lattice) | |
quantvals = maptype1_quantvals(); | |
break; | |
case 2: | |
// every value (c->entries*c->dim total) specified explicitly | |
quantvals = entries * dim; | |
break; | |
} | |
// quantized values | |
for (i = 0; i < quantvals; i++) { | |
opb.write(Math.abs(quantlist[i]), q_quant); | |
} | |
} | |
break; | |
default: | |
// error case; we don't have any other map types now | |
return (-1); | |
} | |
return (0); | |
} | |
// unpacks a codebook from the packet buffer into the codebook struct, | |
// readies the codebook auxiliary structures for decode | |
int unpack(Buffer opb) { | |
int i; | |
// memset(s,0,sizeof(static_codebook)); | |
// make sure alignment is correct | |
if (opb.read(24) != 0x564342) { | |
// goto _eofout; | |
clear(); | |
return (-1); | |
} | |
// first the basic parameters | |
dim = opb.read(16); | |
entries = opb.read(24); | |
if (entries == -1) { | |
// goto _eofout; | |
clear(); | |
return (-1); | |
} | |
// codeword ordering.... length ordered or unordered? | |
switch (opb.read(1)) { | |
case 0: | |
// unordered | |
lengthlist = new int[entries]; | |
// allocated but unused entries? | |
if (opb.read(1) != 0) { | |
// yes, unused entries | |
for (i = 0; i < entries; i++) { | |
if (opb.read(1) != 0) { | |
int num = opb.read(5); | |
if (num == -1) { | |
// goto _eofout; | |
clear(); | |
return (-1); | |
} | |
lengthlist[i] = num + 1; | |
} else { | |
lengthlist[i] = 0; | |
} | |
} | |
} else { | |
// all entries used; no tagging | |
for (i = 0; i < entries; i++) { | |
int num = opb.read(5); | |
if (num == -1) { | |
// goto _eofout; | |
clear(); | |
return (-1); | |
} | |
lengthlist[i] = num + 1; | |
} | |
} | |
break; | |
case 1: | |
// ordered | |
{ | |
int length = opb.read(5) + 1; | |
lengthlist = new int[entries]; | |
for (i = 0; i < entries;) { | |
int num = opb.read(Util.ilog(entries - i)); | |
if (num == -1) { | |
// goto _eofout; | |
clear(); | |
return (-1); | |
} | |
for (int j = 0; j < num; j++, i++) { | |
lengthlist[i] = length; | |
} | |
length++; | |
} | |
} | |
break; | |
default: | |
// EOF | |
return (-1); | |
} | |
// Do we have a mapping to unpack? | |
switch ((maptype = opb.read(4))) { | |
case 0: | |
// no mapping | |
break; | |
case 1: | |
case 2: | |
// implicitly populated value mapping | |
// explicitly populated value mapping | |
q_min = opb.read(32); | |
q_delta = opb.read(32); | |
q_quant = opb.read(4) + 1; | |
q_sequencep = opb.read(1); | |
{ | |
int quantvals = 0; | |
switch (maptype) { | |
case 1: | |
quantvals = maptype1_quantvals(); | |
break; | |
case 2: | |
quantvals = entries * dim; | |
break; | |
} | |
// quantized values | |
quantlist = new int[quantvals]; | |
for (i = 0; i < quantvals; i++) { | |
quantlist[i] = opb.read(q_quant); | |
} | |
if (quantlist[quantvals - 1] == -1) { | |
// goto _eofout; | |
clear(); | |
return (-1); | |
} | |
} | |
break; | |
default: | |
// goto _eofout; | |
clear(); | |
return (-1); | |
} | |
// all set | |
return (0); | |
// _errout: | |
// _eofout: | |
// vorbis_staticbook_clear(s); | |
// return(-1); | |
} | |
// there might be a straightforward one-line way to do the below | |
// that's portable and totally safe against roundoff, but I haven't | |
// thought of it. Therefore, we opt on the side of caution | |
private int maptype1_quantvals() { | |
int vals = (int) (Math.floor(Math.pow(entries, 1. / dim))); | |
// the above *should* be reliable, but we'll not assume that FP is | |
// ever reliable when bitstream sync is at stake; verify via integer | |
// means that vals really is the greatest value of dim for which | |
// vals^b->bim <= b->entries | |
// treat the above as an initial guess | |
while (true) { | |
int acc = 1; | |
int acc1 = 1; | |
for (int i = 0; i < dim; i++) { | |
acc *= vals; | |
acc1 *= vals + 1; | |
} | |
if (acc <= entries && acc1 > entries) { | |
return (vals); | |
} else { | |
if (acc > entries) { | |
vals--; | |
} else { | |
vals++; | |
} | |
} | |
} | |
} | |
void clear() { | |
} | |
// unpack the quantized list of values for encode/decode | |
// we need to deal with two map types: in map type 1, the values are | |
// generated algorithmically (each column of the vector counts through | |
// the values in the quant vector). in map type 2, all the values came | |
// in in an explicit list. Both value lists must be unpacked | |
float[] unquantize() { | |
if (maptype == 1 || maptype == 2) { | |
int quantvals; | |
float mindel = float32_unpack(q_min); | |
float delta = float32_unpack(q_delta); | |
float[] r = new float[entries * dim]; | |
// maptype 1 and 2 both use a quantized value vector, but | |
// different sizes | |
switch (maptype) { | |
case 1: | |
// most of the time, entries%dimensions == 0, but we need to be | |
// well defined. We define that the possible vales at each | |
// scalar is values == entries/dim. If entries%dim != 0, we'll | |
// have 'too few' values (values*dim<entries), which means that | |
// we'll have 'left over' entries; left over entries use zeroed | |
// values (and are wasted). So don't generate codebooks like that | |
quantvals = maptype1_quantvals(); | |
for (int j = 0; j < entries; j++) { | |
float last = 0.f; | |
int indexdiv = 1; | |
for (int k = 0; k < dim; k++) { | |
int index = (j / indexdiv) % quantvals; | |
float val = quantlist[index]; | |
val = Math.abs(val) * delta + mindel + last; | |
if (q_sequencep != 0) | |
last = val; | |
r[j * dim + k] = val; | |
indexdiv *= quantvals; | |
} | |
} | |
break; | |
case 2: | |
for (int j = 0; j < entries; j++) { | |
float last = 0.f; | |
for (int k = 0; k < dim; k++) { | |
float val = quantlist[j * dim + k]; | |
// if((j*dim+k)==0){System.err.println(" | 0 -> "+val+" | ");} | |
val = Math.abs(val) * delta + mindel + last; | |
if (q_sequencep != 0) | |
last = val; | |
r[j * dim + k] = val; | |
// if((j*dim+k)==0){System.err.println(" $ r[0] -> "+r[0]+" | ");} | |
} | |
} | |
// System.err.println("\nr[0]="+r[0]); | |
} | |
return (r); | |
} | |
return (null); | |
} | |
// 32 bit float (not IEEE; nonnormalized mantissa + | |
// biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm | |
// Why not IEEE? It's just not that important here. | |
static final int VQ_FEXP = 10; | |
static final int VQ_FMAN = 21; | |
static final int VQ_FEXP_BIAS = 768; // bias toward values smaller than 1. | |
// doesn't currently guard under/overflow | |
static long float32_pack(float val) { | |
int sign = 0; | |
int exp; | |
int mant; | |
if (val < 0) { | |
sign = 0x80000000; | |
val = -val; | |
} | |
exp = (int) Math.floor(Math.log(val) / Math.log(2)); | |
mant = (int) Math.rint(Math.pow(val, (VQ_FMAN - 1) - exp)); | |
exp = (exp + VQ_FEXP_BIAS) << VQ_FMAN; | |
return (sign | exp | mant); | |
} | |
static float float32_unpack(int val) { | |
float mant = val & 0x1fffff; | |
float exp = (val & 0x7fe00000) >>> VQ_FMAN; | |
if ((val & 0x80000000) != 0) | |
mant = -mant; | |
return (ldexp(mant, ((int) exp) - (VQ_FMAN - 1) - VQ_FEXP_BIAS)); | |
} | |
static float ldexp(float foo, int e) { | |
return (float) (foo * Math.pow(2, e)); | |
} | |
} | |