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 && config.isSBREnabled()) {
      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]);
    }
  }
  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 && config.isSBREnabled()) {
      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]);
      } else scelfe.getSBR().process(data[channel], null);
    }
    return chs;
  }