de.jarnbjo.vorbis.AudioPacket Maven / Gradle / Ivy
/*
* $ProjectName$
* $ProjectRevision$
* -----------------------------------------------------------
* $Id: AudioPacket.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
* -----------------------------------------------------------
*
* $Author: jarnbjo $
*
* Description:
*
* Copyright 2002-2003 Tor-Einar Jarnbjo
* -----------------------------------------------------------
*
* Change History
* -----------------------------------------------------------
* $Log: AudioPacket.java,v $
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
* no message
*/
package de.jarnbjo.vorbis;
import de.jarnbjo.util.io.BitInputStream;
import java.io.IOException;
class AudioPacket {
final private int modeNumber;
final private Mode mode;
final private Mapping mapping;
final private int n; // block size
final private boolean blockFlag;
private boolean previousWindowFlag, nextWindowFlag;
final private int windowCenter, leftWindowStart, leftWindowEnd, leftN,
rightWindowStart, rightWindowEnd, rightN;
final private float[] window;
final private float[][] pcm;
final private int[][] pcmInt;
final private Floor[] channelFloors;
final private boolean[] noResidues;
private final float[][] windows = new float[8][];
protected AudioPacket(
final VorbisStream vorbis, final BitInputStream source)
throws IOException {
final SetupHeader sHeader = vorbis.getSetupHeader();
final IdentificationHeader iHeader = vorbis.getIdentificationHeader();
final Mode[] modes = sHeader.getModes();
final Mapping[] mappings = sHeader.getMappings();
final Residue[] residues = sHeader.getResidues();
final int channels = iHeader.getChannels();
if (source.getInt(1) != 0) {
throw new VorbisFormatException("Packet type mismatch "
+ "when trying to create an audio packet.");
}
modeNumber = source.getInt(Util.ilog(modes.length - 1));
try {
mode = modes[modeNumber];
} catch (ArrayIndexOutOfBoundsException e) {
throw new VorbisFormatException(
"Reference to invalid mode in audio packet.");
}
mapping = mappings[mode.getMapping()];
final int[] magnitudes = mapping.getMagnitudes();
final int[] angles = mapping.getAngles();
blockFlag = mode.getBlockFlag();
final int blockSize0 = iHeader.getBlockSize0();
final int blockSize1 = iHeader.getBlockSize1();
n = blockFlag ? blockSize1 : blockSize0;
if (blockFlag) {
previousWindowFlag = source.getBit();
nextWindowFlag = source.getBit();
}
windowCenter = n / 2;
if (blockFlag && !previousWindowFlag) {
leftWindowStart = n / 4 - blockSize0 / 4;
leftWindowEnd = n / 4 + blockSize0 / 4;
leftN = blockSize0 / 2;
} else {
leftWindowStart = 0;
leftWindowEnd = n / 2;
leftN = windowCenter;
}
if (blockFlag && !nextWindowFlag) {
rightWindowStart = n * 3 / 4 - blockSize0 / 4;
rightWindowEnd = n * 3 / 4 + blockSize0 / 4;
rightN = blockSize0 / 2;
} else {
rightWindowStart = windowCenter;
rightWindowEnd = n;
rightN = n / 2;
}
window = getComputedWindow(); //new double[n];
channelFloors = new Floor[channels];
noResidues = new boolean[channels];
pcm = new float[channels][n];
pcmInt = new int[channels][n];
boolean allFloorsEmpty = true;
for (int i = 0; i < channels; i++) {
int submapNumber = mapping.getMux()[i];
int floorNumber = mapping.getSubmapFloors()[submapNumber];
Floor decodedFloor = sHeader.getFloors()[floorNumber]
.decodeFloor(vorbis, source);
channelFloors[i] = decodedFloor;
noResidues[i] = decodedFloor == null;
if (decodedFloor != null) {
allFloorsEmpty = false;
}
}
if (allFloorsEmpty) {
return;
}
for (int i = 0; i < magnitudes.length; i++) {
if (!noResidues[magnitudes[i]]
|| !noResidues[angles[i]]) {
noResidues[magnitudes[i]] = false;
noResidues[angles[i]] = false;
}
}
Residue[] decodedResidues = new Residue[mapping.getSubmaps()];
for (int i = 0; i < mapping.getSubmaps(); i++) {
int ch = 0;
boolean[] doNotDecodeFlags = new boolean[channels];
for (int j = 0; j < channels; j++) {
if (mapping.getMux()[j] == i) {
doNotDecodeFlags[ch++] = noResidues[j];
}
}
int residueNumber = mapping.getSubmapResidues()[i];
Residue residue = residues[residueNumber];
residue.decodeResidue(
vorbis, source, mode, ch, doNotDecodeFlags, pcm);
}
for (int i = mapping.getCouplingSteps() - 1; i >= 0; i--) {
double newA = 0, newM = 0;
final float[] magnitudeVector = pcm[magnitudes[i]];
final float[] angleVector = pcm[angles[i]];
for (int j = 0; j < magnitudeVector.length; j++) {
float a = angleVector[j];
float m = magnitudeVector[j];
if (a > 0) {
//magnitudeVector[j]=m;
angleVector[j] = m > 0 ? m - a : m + a;
} else {
magnitudeVector[j] = m > 0 ? m + a : m - a;
angleVector[j] = m;
}
}
}
for (int i = 0; i < channels; i++) {
if (channelFloors[i] != null) {
channelFloors[i].computeFloor(pcm[i]);
}
}
// perform an inverse MDCT to all channels
for (int i = 0; i < channels; i++) {
MdctFloat mdct = blockFlag ? iHeader.getMdct1()
: iHeader.getMdct0();
mdct.imdct(pcm[i], window, pcmInt[i]);
}
}
private float[] getComputedWindow() {
int ix = (blockFlag ? 4 : 0) + (previousWindowFlag ? 2 : 0)
+ (nextWindowFlag ? 1 : 0);
float[] w = windows[ix];
if (w == null) {
w = new float[n];
for (int i = 0; i < leftN; i++) {
float x = (float) ((i + .5) / leftN * Math.PI / 2.);
x = (float) Math.sin(x);
x *= x;
x *= (float) Math.PI / 2.;
x = (float) Math.sin(x);
w[i + leftWindowStart] = x;
}
for (int i = leftWindowEnd; i < rightWindowStart;) {
w[i++] = 1f;
}
for (int i = 0; i < rightN; i++) {
float x = (float) ((rightN - i - .5) / rightN * Math.PI / 2.);
x = (float) Math.sin(x);
x *= x;
x *= (float) Math.PI / 2.;
x = (float) Math.sin(x);
w[i + rightWindowStart] = x;
}
windows[ix] = w;
}
return w;
}
protected int getNumberOfSamples() {
return rightWindowStart - leftWindowStart;
}
protected int getPcm(
final AudioPacket previousPacket, final int[][] buffer) {
int channels = pcm.length;
int val;
// copy left window flank and mix with right window flank from
// the previous audio packet
for (int i = 0; i < channels; i++) {
int j1 = 0, j2 = previousPacket.rightWindowStart;
final int[] ppcm = previousPacket.pcmInt[i];
final int[] tpcm = pcmInt[i];
final int[] target = buffer[i];
for (int j = leftWindowStart; j < leftWindowEnd; j++) {
val = ppcm[j2++] + tpcm[j];
if (val > 32767) {
val = 32767;
}
if (val < -32768) {
val = -32768;
}
target[j1++] = val;
}
}
// use System.arraycopy to copy the middle part (if any)
// of the window
if (leftWindowEnd + 1 < rightWindowStart) {
for (int i = 0; i < channels; i++) {
System.arraycopy(pcmInt[i], leftWindowEnd, buffer[i],
leftWindowEnd - leftWindowStart,
rightWindowStart - leftWindowEnd);
}
}
return rightWindowStart - leftWindowStart;
}
protected void getPcm(
final AudioPacket previousPacket, final byte[] buffer) {
int channels = pcm.length;
int val;
// copy left window flank and mix with right window flank from
// the previous audio packet
for (int i = 0; i < channels; i++) {
int ix = 0, j2 = previousPacket.rightWindowStart;
final int[] ppcm = previousPacket.pcmInt[i];
final int[] tpcm = pcmInt[i];
for (int j = leftWindowStart; j < leftWindowEnd; j++) {
val = ppcm[j2++] + tpcm[j];
if (val > 32767) {
val = 32767;
}
if (val < -32768) {
val = -32768;
}
buffer[ix + (i * 2) + 1] = (byte) (val & 0xff);
buffer[ix + (i * 2)] = (byte) ((val >> 8) & 0xff);
ix += channels * 2;
}
ix = (leftWindowEnd - leftWindowStart) * channels * 2;
for (int j = leftWindowEnd; j < rightWindowStart; j++) {
val = tpcm[j];
if (val > 32767) {
val = 32767;
}
if (val < -32768) {
val = -32768;
}
buffer[ix + (i * 2) + 1] = (byte) (val & 0xff);
buffer[ix + (i * 2)] = (byte) ((val >> 8) & 0xff);
ix += channels * 2;
}
}
}
protected float[] getWindow() {
return window;
}
protected int getLeftWindowStart() {
return leftWindowStart;
}
protected int getLeftWindowEnd() {
return leftWindowEnd;
}
protected int getRightWindowStart() {
return rightWindowStart;
}
protected int getRightWindowEnd() {
return rightWindowEnd;
}
public int[][] getPcm() {
return pcmInt;
}
public float[][] getFreqencyDomain() {
return pcm;
}
}