/* * 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.filterbank; import net.sourceforge.jaad.aac.AACException; import net.sourceforge.jaad.aac.syntax.Constants; import net.sourceforge.jaad.aac.syntax.ICSInfo.WindowSequence; public class FilterBank implements Constants, SineWindows, KBDWindows { private final float[][] LONG_WINDOWS;// = {SINE_LONG, KBD_LONG}; private final float[][] SHORT_WINDOWS;// = {SINE_SHORT, KBD_SHORT}; private final int length, shortLen, mid, trans; private final MDCT mdctShort, mdctLong; private final float[] buf; private final float[][] overlaps; public FilterBank(boolean smallFrames, int channels) throws AACException { if(smallFrames) { length = WINDOW_SMALL_LEN_LONG; shortLen = WINDOW_SMALL_LEN_SHORT; LONG_WINDOWS = new float[][]{SINE_960, KBD_960}; SHORT_WINDOWS = new float[][]{SINE_120, KBD_120}; } else { length = WINDOW_LEN_LONG; shortLen = WINDOW_LEN_SHORT; LONG_WINDOWS = new float[][]{SINE_1024, KBD_1024}; SHORT_WINDOWS = new float[][]{SINE_128, KBD_128}; } mid = (length-shortLen)/2; trans = shortLen/2; mdctShort = new MDCT(shortLen*2); mdctLong = new MDCT(length*2); overlaps = new float[channels][length]; buf = new float[2*length]; } public void process(WindowSequence windowSequence, int windowShape, int windowShapePrev, float[] in, float[] out, int channel) { int i; float[] overlap = overlaps[channel]; switch(windowSequence) { case ONLY_LONG_SEQUENCE: mdctLong.process(in, 0, buf, 0); //add second half output of previous frame to windowed output of current frame for(i = 0; i<length; i++) { out[i] = overlap[i]+(buf[i]*LONG_WINDOWS[windowShapePrev][i]); } //window the second half and save as overlap for next frame for(i = 0; i<length; i++) { overlap[i] = buf[length+i]*LONG_WINDOWS[windowShape][length-1-i]; } break; case LONG_START_SEQUENCE: mdctLong.process(in, 0, buf, 0); //add second half output of previous frame to windowed output of current frame for(i = 0; i<length; i++) { out[i] = overlap[i]+(buf[i]*LONG_WINDOWS[windowShapePrev][i]); } //window the second half and save as overlap for next frame for(i = 0; i<mid; i++) { overlap[i] = buf[length+i]; } for(i = 0; i<shortLen; i++) { overlap[mid+i] = buf[length+mid+i]*SHORT_WINDOWS[windowShape][shortLen-i-1]; } for(i = 0; i<mid; i++) { overlap[mid+shortLen+i] = 0; } break; case EIGHT_SHORT_SEQUENCE: for(i = 0; i<8; i++) { mdctShort.process(in, i*shortLen, buf, 2*i*shortLen); } //add second half output of previous frame to windowed output of current frame for(i = 0; i<mid; i++) { out[i] = overlap[i]; } for(i = 0; i<shortLen; i++) { out[mid+i] = overlap[mid+i]+(buf[i]*SHORT_WINDOWS[windowShapePrev][i]); out[mid+1*shortLen+i] = overlap[mid+shortLen*1+i]+(buf[shortLen*1+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*2+i]*SHORT_WINDOWS[windowShape][i]); out[mid+2*shortLen+i] = overlap[mid+shortLen*2+i]+(buf[shortLen*3+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*4+i]*SHORT_WINDOWS[windowShape][i]); out[mid+3*shortLen+i] = overlap[mid+shortLen*3+i]+(buf[shortLen*5+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*6+i]*SHORT_WINDOWS[windowShape][i]); if(i<trans) out[mid+4*shortLen+i] = overlap[mid+shortLen*4+i]+(buf[shortLen*7+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*8+i]*SHORT_WINDOWS[windowShape][i]); } //window the second half and save as overlap for next frame for(i = 0; i<shortLen; i++) { if(i>=trans) overlap[mid+4*shortLen+i-length] = (buf[shortLen*7+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*8+i]*SHORT_WINDOWS[windowShape][i]); overlap[mid+5*shortLen+i-length] = (buf[shortLen*9+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*10+i]*SHORT_WINDOWS[windowShape][i]); overlap[mid+6*shortLen+i-length] = (buf[shortLen*11+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*12+i]*SHORT_WINDOWS[windowShape][i]); overlap[mid+7*shortLen+i-length] = (buf[shortLen*13+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*14+i]*SHORT_WINDOWS[windowShape][i]); overlap[mid+8*shortLen+i-length] = (buf[shortLen*15+i]*SHORT_WINDOWS[windowShape][shortLen-1-i]); } for(i = 0; i<mid; i++) { overlap[mid+shortLen+i] = 0; } break; case LONG_STOP_SEQUENCE: mdctLong.process(in, 0, buf, 0); //add second half output of previous frame to windowed output of current frame //construct first half window using padding with 1's and 0's for(i = 0; i<mid; i++) { out[i] = overlap[i]; } for(i = 0; i<shortLen; i++) { out[mid+i] = overlap[mid+i]+(buf[mid+i]*SHORT_WINDOWS[windowShapePrev][i]); } for(i = 0; i<mid; i++) { out[mid+shortLen+i] = overlap[mid+shortLen+i]+buf[mid+shortLen+i]; } //window the second half and save as overlap for next frame for(i = 0; i<length; i++) { overlap[i] = buf[length+i]*LONG_WINDOWS[windowShape][length-1-i]; } break; } } //only for LTP: no overlapping, no short blocks public void processLTP(WindowSequence windowSequence, int windowShape, int windowShapePrev, float[] in, float[] out) { int i; switch(windowSequence) { case ONLY_LONG_SEQUENCE: for(i = length-1; i>=0; i--) { buf[i] = in[i]*LONG_WINDOWS[windowShapePrev][i]; buf[i+length] = in[i+length]*LONG_WINDOWS[windowShape][length-1-i]; } break; case LONG_START_SEQUENCE: for(i = 0; i<length; i++) { buf[i] = in[i]*LONG_WINDOWS[windowShapePrev][i]; } for(i = 0; i<mid; i++) { buf[i+length] = in[i+length]; } for(i = 0; i<shortLen; i++) { buf[i+length+mid] = in[i+length+mid]*SHORT_WINDOWS[windowShape][shortLen-1-i]; } for(i = 0; i<mid; i++) { buf[i+length+mid+shortLen] = 0; } break; case LONG_STOP_SEQUENCE: for(i = 0; i<mid; i++) { buf[i] = 0; } for(i = 0; i<shortLen; i++) { buf[i+mid] = in[i+mid]*SHORT_WINDOWS[windowShapePrev][i]; } for(i = 0; i<mid; i++) { buf[i+mid+shortLen] = in[i+mid+shortLen]; } for(i = 0; i<length; i++) { buf[i+length] = in[i+length]*LONG_WINDOWS[windowShape][length-1-i]; } break; } mdctLong.processForward(buf, out); } public float[] getOverlap(int channel) { return overlaps[channel]; } }