All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy