Package net.sourceforge.jaad.aac.syntax

Source Code of net.sourceforge.jaad.aac.syntax.SyntacticElements

/*
*  Copyright (C) 2011 in-somnia
*
*  This file is part of JAAD.
*
*  JAAD is free software; you can redistribute it and/or modify it
*  under the terms of the GNU Lesser General Public License as
*  published by the Free Software Foundation; either version 3 of the
*  License, or (at your option) any later version.
*
*  JAAD 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 Lesser General
*  Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library.
*  If not, see <http://www.gnu.org/licenses/>.
*/
package net.sourceforge.jaad.aac.syntax;

import net.sourceforge.jaad.aac.AACException;
import net.sourceforge.jaad.aac.ChannelConfiguration;
import net.sourceforge.jaad.aac.DecoderConfig;
import net.sourceforge.jaad.aac.Profile;
import net.sourceforge.jaad.aac.SampleBuffer;
import net.sourceforge.jaad.aac.SampleFrequency;
import net.sourceforge.jaad.aac.filterbank.FilterBank;
import net.sourceforge.jaad.aac.tools.LTPrediction;
import net.sourceforge.jaad.aac.sbr2.SBR;
import net.sourceforge.jaad.aac.tools.IS;
import net.sourceforge.jaad.aac.tools.MS;
import java.util.logging.Level;

public class SyntacticElements implements Constants {

  //global properties
  private DecoderConfig config;
  private boolean sbrPresent, psPresent;
  private int bitsRead;
  //elements
  private final PCE pce;
  private final Element[] elements; //SCE, LFE and CPE
  private final CCE[] cces;
  private final DSE[] dses;
  private final FIL[] fils;
  private int curElem, curCCE, curDSE, curFIL;
  private float[][] data;

  public SyntacticElements(DecoderConfig config) {
    this.config = config;

    pce = new PCE();
    elements = new Element[4*MAX_ELEMENTS];
    cces = new CCE[MAX_ELEMENTS];
    dses = new DSE[MAX_ELEMENTS];
    fils = new FIL[MAX_ELEMENTS];

    startNewFrame();
  }

  public final void startNewFrame() {
    curElem = 0;
    curCCE = 0;
    curDSE = 0;
    curFIL = 0;
    sbrPresent = false;
    psPresent = false;
    bitsRead = 0;
  }

  public void decode(BitStream in) throws AACException {
    final int start = in.getPosition(); //should be 0

    int type;
    Element prev = null;
    boolean content = true;
    if(!config.getProfile().isErrorResilientProfile()) {
      while(content&&(type = in.readBits(3))!=ELEMENT_END) {
        switch(type) {
          case ELEMENT_SCE:
          case ELEMENT_LFE:
            LOGGER.finest("SCE");
            prev = decodeSCE_LFE(in);
            break;
          case ELEMENT_CPE:
            LOGGER.finest("CPE");
            prev = decodeCPE(in);
            break;
          case ELEMENT_CCE:
            LOGGER.finest("CCE");
            decodeCCE(in);
            prev = null;
            break;
          case ELEMENT_DSE:
            LOGGER.finest("DSE");
            decodeDSE(in);
            prev = null;
            break;
          case ELEMENT_PCE:
            LOGGER.finest("PCE");
            decodePCE(in);
            prev = null;
            break;
          case ELEMENT_FIL:
            LOGGER.finest("FIL");
            decodeFIL(in, prev);
            prev = null;
            break;
        }
      }
      LOGGER.finest("END");
      content = false;
      prev = null;
    }
    else {
      //error resilient raw data block
      switch(config.getChannelConfiguration()) {
        case CHANNEL_CONFIG_MONO:
          decodeSCE_LFE(in);
          break;
        case CHANNEL_CONFIG_STEREO:
          decodeCPE(in);
          break;
        case CHANNEL_CONFIG_STEREO_PLUS_CENTER:
          decodeSCE_LFE(in);
          decodeCPE(in);
          break;
        case CHANNEL_CONFIG_STEREO_PLUS_CENTER_PLUS_REAR_MONO:
          decodeSCE_LFE(in);
          decodeCPE(in);
          decodeSCE_LFE(in);
          break;
        case CHANNEL_CONFIG_FIVE:
          decodeSCE_LFE(in);
          decodeCPE(in);
          decodeCPE(in);
          break;
        case CHANNEL_CONFIG_FIVE_PLUS_ONE:
          decodeSCE_LFE(in);
          decodeCPE(in);
          decodeCPE(in);
          decodeSCE_LFE(in);
          break;
        case CHANNEL_CONFIG_SEVEN_PLUS_ONE:
          decodeSCE_LFE(in);
          decodeCPE(in);
          decodeCPE(in);
          decodeCPE(in);
          decodeSCE_LFE(in);
          break;
        default:
          throw new AACException("unsupported channel configuration for error resilience: "+config.getChannelConfiguration());
      }
    }
    in.byteAlign();

    bitsRead = in.getPosition()-start;
  }

  private Element decodeSCE_LFE(BitStream in) throws AACException {
    if(elements[curElem]==null) elements[curElem] = new SCE_LFE(config.getFrameLength());
    ((SCE_LFE) elements[curElem]).decode(in, config);
    curElem++;
    return elements[curElem-1];
  }

  private Element decodeCPE(BitStream in) throws AACException {
    if(elements[curElem]==null) elements[curElem] = new CPE(config.getFrameLength());
    ((CPE) elements[curElem]).decode(in, config);
    curElem++;
    return elements[curElem-1];
  }

  private void decodeCCE(BitStream in) throws AACException {
    if(curCCE==MAX_ELEMENTS) throw new AACException("too much CCE elements");
    if(cces[curCCE]==null) cces[curCCE] = new CCE(config.getFrameLength());
    cces[curCCE].decode(in, config);
    curCCE++;
  }

  private void decodeDSE(BitStream in) throws AACException {
    if(curDSE==MAX_ELEMENTS) throw new AACException("too much CCE elements");
    if(dses[curDSE]==null) dses[curDSE] = new DSE();
    dses[curDSE].decode(in);
    curDSE++;
  }

  private void decodePCE(BitStream in) throws AACException {
    pce.decode(in);
    config.setProfile(pce.getProfile());
    config.setSampleFrequency(pce.getSampleFrequency());
    config.setChannelConfiguration(ChannelConfiguration.forInt(pce.getChannelCount()));
  }

  private void decodeFIL(BitStream in, Element prev) throws AACException {
    if(curFIL==MAX_ELEMENTS) throw new AACException("too much FIL elements");
    if(fils[curFIL]==null) fils[curFIL] = new FIL(config.isSBRDownSampled());
    fils[curFIL].decode(in, prev, config.getSampleFrequency());
    curFIL++;

    if(prev!=null&&prev.isSBRPresent()) {
      sbrPresent = true;
      if(!psPresent&&prev.getSBR().isPSUsed()) psPresent = true;
    }
  }

  public void process(FilterBank filterBank) throws AACException {
    final Profile profile = config.getProfile();
    final SampleFrequency sf = config.getSampleFrequency();
    //final ChannelConfiguration channels = config.getChannelConfiguration();

    int chs = config.getChannelConfiguration().getChannelCount();
    if(chs==1&&psPresent) chs++;
    final int mult = sbrPresent ? 2 : 1;
    //only reallocate if needed
    if(data==null||chs!=data.length||(mult*config.getFrameLength())!=data[0].length) data = new float[chs][mult*config.getFrameLength()];

    int channel = 0;
    Element e;
    SCE_LFE scelfe;
    CPE cpe;
    for(int i = 0; i<elements.length&&channel<chs; i++) {
      e = elements[i];
      if(e==null) continue;
      if(e instanceof SCE_LFE) {
        scelfe = (SCE_LFE) e;
        channel += processSingle(scelfe, filterBank, channel, profile, sf);
      }
      else if(e instanceof CPE) {
        cpe = (CPE) e;
        processPair(cpe, filterBank, channel, profile, sf);
        channel += 2;
      }
      else if(e instanceof CCE) {
        //applies invquant and save the result in the CCE
        ((CCE) e).process();
        channel++;
      }
    }
  }

  private int processSingle(SCE_LFE scelfe, FilterBank filterBank, int channel, Profile profile, SampleFrequency sf) throws AACException {
    final ICStream ics = scelfe.getICStream();
    final ICSInfo info = ics.getInfo();
    final LTPrediction ltp = info.getLTPrediction1();
    final int elementID = scelfe.getElementInstanceTag();

    //inverse quantization
    final float[] iqData = ics.getInvQuantData();

    //prediction
    if(profile.equals(Profile.AAC_MAIN)&&info.isICPredictionPresent()) info.getICPrediction().process(ics, iqData, sf);
    if(LTPrediction.isLTPProfile(profile)&&info.isLTPrediction1Present()) ltp.process(ics, iqData, filterBank, sf);

    //dependent coupling
    processDependentCoupling(false, elementID, CCE.BEFORE_TNS, iqData, null);

    //TNS
    if(ics.isTNSDataPresent()) ics.getTNS().process(ics, iqData, sf, false);

    //dependent coupling
    processDependentCoupling(false, elementID, CCE.AFTER_TNS, iqData, null);

    //filterbank
    filterBank.process(info.getWindowSequence(), info.getWindowShape(ICSInfo.CURRENT), info.getWindowShape(ICSInfo.PREVIOUS), iqData, data[channel], channel);

    if(LTPrediction.isLTPProfile(profile)) ltp.updateState(data[channel], filterBank.getOverlap(channel), profile);

    //dependent coupling
    processIndependentCoupling(false, elementID, data[channel], null);

    //gain control
    if(ics.isGainControlPresent()) ics.getGainControl().process(iqData, info.getWindowShape(ICSInfo.CURRENT), info.getWindowShape(ICSInfo.PREVIOUS), info.getWindowSequence());

    //SBR
    int chs = 1;
    if(sbrPresent) {
      if(data[channel].length==config.getFrameLength()) LOGGER.log(Level.WARNING, "SBR data present, but buffer has normal size!");
      final SBR sbr = scelfe.getSBR();
      if(sbr.isPSUsed()) {
        chs = 2;
        scelfe.getSBR().process(data[channel], data[channel+1], false);
      }
      else scelfe.getSBR().process(data[channel], null, false);
    }
    return chs;
  }

  private void processPair(CPE cpe, FilterBank filterBank, int channel, Profile profile, SampleFrequency sf) throws AACException {
    final ICStream ics1 = cpe.getLeftChannel();
    final ICStream ics2 = cpe.getRightChannel();
    final ICSInfo info1 = ics1.getInfo();
    final ICSInfo info2 = ics2.getInfo();
    final LTPrediction ltp1 = info1.getLTPrediction1();
    final LTPrediction ltp2 = cpe.isCommonWindow() ? info1.getLTPrediction2() : info2.getLTPrediction1();
    final int elementID = cpe.getElementInstanceTag();

    //inverse quantization
    final float[] iqData1 = ics1.getInvQuantData();
    final float[] iqData2 = ics2.getInvQuantData();

    //MS
    if(cpe.isCommonWindow()&&cpe.isMSMaskPresent()) MS.process(cpe, iqData1, iqData2);
    //main prediction
    if(profile.equals(Profile.AAC_MAIN)) {
      if(info1.isICPredictionPresent()) info1.getICPrediction().process(ics1, iqData1, sf);
      if(info2.isICPredictionPresent()) info2.getICPrediction().process(ics2, iqData2, sf);
    }
    //IS
    IS.process(cpe, iqData1, iqData2);

    //LTP
    if(LTPrediction.isLTPProfile(profile)) {
      if(info1.isLTPrediction1Present()) ltp1.process(ics1, iqData1, filterBank, sf);
      if(cpe.isCommonWindow()&&info1.isLTPrediction2Present()) ltp2.process(ics2, iqData2, filterBank, sf);
      else if(info2.isLTPrediction1Present()) ltp2.process(ics2, iqData2, filterBank, sf);
    }

    //dependent coupling
    processDependentCoupling(true, elementID, CCE.BEFORE_TNS, iqData1, iqData2);

    //TNS
    if(ics1.isTNSDataPresent()) ics1.getTNS().process(ics1, iqData1, sf, false);
    if(ics2.isTNSDataPresent()) ics2.getTNS().process(ics2, iqData2, sf, false);

    //dependent coupling
    processDependentCoupling(true, elementID, CCE.AFTER_TNS, iqData1, iqData2);

    //filterbank
    filterBank.process(info1.getWindowSequence(), info1.getWindowShape(ICSInfo.CURRENT), info1.getWindowShape(ICSInfo.PREVIOUS), iqData1, data[channel], channel);
    filterBank.process(info2.getWindowSequence(), info2.getWindowShape(ICSInfo.CURRENT), info2.getWindowShape(ICSInfo.PREVIOUS), iqData2, data[channel+1], channel+1);

    if(LTPrediction.isLTPProfile(profile)) {
      ltp1.updateState(data[channel], filterBank.getOverlap(channel), profile);
      ltp2.updateState(data[channel+1], filterBank.getOverlap(channel+1), profile);
    }

    //independent coupling
    processIndependentCoupling(true, elementID, data[channel], data[channel+1]);

    //gain control
    if(ics1.isGainControlPresent()) ics1.getGainControl().process(iqData1, info1.getWindowShape(ICSInfo.CURRENT), info1.getWindowShape(ICSInfo.PREVIOUS), info1.getWindowSequence());
    if(ics2.isGainControlPresent()) ics2.getGainControl().process(iqData2, info2.getWindowShape(ICSInfo.CURRENT), info2.getWindowShape(ICSInfo.PREVIOUS), info2.getWindowSequence());

    //SBR
    if(sbrPresent) {
      //if(data[channel].length==config.getFrameLength()) LOGGER.log(Level.WARNING, "SBR data present, but buffer has normal size!");
      cpe.getSBR().process(data[channel], data[channel+1], false);
    }
  }

  private void processIndependentCoupling(boolean channelPair, int elementID, float[] data1, float[] data2) {
    int index, c, chSelect;
    CCE cce;
    for(int i = 0; i<cces.length; i++) {
      cce = cces[i];
      index = 0;
      if(cce!=null&&cce.getCouplingPoint()==CCE.AFTER_IMDCT) {
        for(c = 0; c<=cce.getCoupledCount(); c++) {
          chSelect = cce.getCHSelect(c);
          if(cce.isChannelPair(c)==channelPair&&cce.getIDSelect(c)==elementID) {
            if(chSelect!=1) {
              cce.applyIndependentCoupling(index, data1);
              if(chSelect!=0) index++;
            }
            if(chSelect!=2) {
              cce.applyIndependentCoupling(index, data2);
              index++;
            }
          }
          else index += 1+((chSelect==3) ? 1 : 0);
        }
      }
    }
  }

  private void processDependentCoupling(boolean channelPair, int elementID, int couplingPoint, float[] data1, float[] data2) {
    int index, c, chSelect;
    CCE cce;
    for(int i = 0; i<cces.length; i++) {
      cce = cces[i];
      index = 0;
      if(cce!=null&&cce.getCouplingPoint()==couplingPoint) {
        for(c = 0; c<=cce.getCoupledCount(); c++) {
          chSelect = cce.getCHSelect(c);
          if(cce.isChannelPair(c)==channelPair&&cce.getIDSelect(c)==elementID) {
            if(chSelect!=1) {
              cce.applyDependentCoupling(index, data1);
              if(chSelect!=0) index++;
            }
            if(chSelect!=2) {
              cce.applyDependentCoupling(index, data2);
              index++;
            }
          }
          else index += 1+((chSelect==3) ? 1 : 0);
        }
      }
    }
  }

  public void sendToOutput(SampleBuffer buffer) {
    final boolean be = buffer.isBigEndian();

    final int chs = data.length;
    final int mult = (sbrPresent) ? 2 : 1;
    final int length = mult*config.getFrameLength();
    final int freq = mult*config.getSampleFrequency().getFrequency();

    byte[] b = buffer.getData();
    if(b.length!=chs*length*2) b = new byte[chs*length*2];

    float[] cur;
    int i, j, off;
    short s;
    for(i = 0; i<chs; i++) {
      cur = data[i];
      for(j = 0; j<length; j++) {
        s = (short) Math.max(Math.min(Math.round(cur[j]), Short.MAX_VALUE), Short.MIN_VALUE);
        off = (j*chs+i)*2;
        if(be) {
          b[off] = (byte) ((s>>8)&BYTE_MASK);
          b[off+1] = (byte) (s&BYTE_MASK);
        }
        else {
          b[off+1] = (byte) ((s>>8)&BYTE_MASK);
          b[off] = (byte) (s&BYTE_MASK);
        }
      }
    }

    buffer.setData(b, freq, chs, 16, bitsRead);
  }
}
TOP

Related Classes of net.sourceforge.jaad.aac.syntax.SyntacticElements

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.