/**
* Copyright 2007 DFKI GmbH.
* All Rights Reserved. Use is subject to license terms.
*
* This file is part of MARY TTS.
*
* MARY TTS 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, version 3 of the License.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package marytts.signalproc.filter;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import marytts.util.data.BufferedDoubleDataSource;
import marytts.util.data.audio.AudioDoubleDataSource;
import marytts.util.data.audio.DDSAudioInputStream;
import marytts.util.signal.SignalProcUtils;
/**
* This class implements a single channel of the complementary filter bank used in [Levine, et. al., 1999] for multiresolution
* sinusoidal modeling.
*
* [Levine, et. al., 1999] Levine, S. N., Verma, T. S., and Smith III, J. O., "Multiresolution sinusoidal modeling for wideband
* audio with modifications", in Proc. of the IEEE ICASSP 1998, Volume 6, Issue , 12-15 May 1998, pp. 3585-3588.
*
* @author Oytun Türk
*/
public class ComplementaryFilterBankChannelAnalyser {
public double[] lpfOut; // Output of lowpass sub-channel
public double[] hpfOut; // Output of highpass sub-channel
public double[] lpfOutInterpolated; // Upsampled version of lowpass sub-channel output
public double lpfOutEnergy; // Energy of output lowpass sub-channel
protected LowPassFilter Hd;
protected LowPassFilter Hb;
protected LowPassFilter Hi;
protected int filterLengthMinusOne;
protected double[] filterNumerator;
public ComplementaryFilterBankChannelAnalyser(int N) {
if (N % 2 != 0)
N++;
filterLengthMinusOne = N;
Hd = new LowPassFilter(0.5 * 0.5, filterLengthMinusOne + 1);
Hb = new LowPassFilter(0.5 * 0.95, (int) (0.5 * filterLengthMinusOne + 1));
Hi = new LowPassFilter(0.5 * 0.5, filterLengthMinusOne + 1);
filterNumerator = new double[1];
filterNumerator[0] = 1.0;
}
public double[] applyToOutputHighComponent(double[] x) {
apply(x);
return hpfOut;
}
public double[] applyToOutputLowComponent(double[] x) {
apply(x);
return lpfOut;
}
public double[] applyToOutputLowInterpolatedComponent(double[] x) {
apply(x);
return lpfOutInterpolated;
}
public void apply(double[] x) {
int i;
double[] lpfOutTmp;
// lpfOutTmp = SignalProcUtils.filter(Hd.getDenumeratorCoefficients(), filterNumerator, x);
lpfOutTmp = Hd.apply(x);
lpfOutTmp = SignalProcUtils.decimate(lpfOutTmp, 2.0);
// lpfOutTmp = SignalProcUtils.filter(Hb.getDenumeratorCoefficients(), filterNumerator, lpfOutTmp);
lpfOutTmp = Hb.apply(lpfOutTmp);
// Interpolation of lowpass channel
lpfOutInterpolated = SignalProcUtils.interpolate(lpfOutTmp, 2.0);
// lpfOutInterpolated = SignalProcUtils.filter(Hi.getDenumeratorCoefficients(), filterNumerator, lpfOutInterpolated);
lpfOutInterpolated = Hi.apply(lpfOutInterpolated);
//
// Energy compensation
double enx = SignalProcUtils.energy(x);
double enxloi = SignalProcUtils.energy(lpfOutInterpolated);
double gxloi = Math.sqrt(enx / enxloi);
for (i = 0; i < lpfOutInterpolated.length; i++)
lpfOutInterpolated[i] *= gxloi;
//
int delay = (int) Math.floor(1.5 * filterLengthMinusOne + 0.5) - 1;
hpfOut = new double[x.length];
for (i = 0; i < x.length - delay; i++)
hpfOut[i] = x[i] - lpfOutInterpolated[i + delay];
for (i = x.length - delay; i < x.length; i++)
hpfOut[i] = 0.0;
delay = (int) Math.floor(0.5 * filterLengthMinusOne + 0.5);
lpfOut = new double[lpfOutTmp.length - delay];
for (i = delay; i < lpfOutTmp.length; i++)
lpfOut[i - delay] = lpfOutTmp[i];
lpfOutEnergy = SignalProcUtils.energy(lpfOut);
}
public static void main(String[] args) throws UnsupportedAudioFileException, IOException {
AudioInputStream inputAudio = AudioSystem.getAudioInputStream(new File(args[0]));
int samplingRate = (int) inputAudio.getFormat().getSampleRate();
AudioDoubleDataSource signal = new AudioDoubleDataSource(inputAudio);
double[] x = signal.getAllData();
int N = 512;
ComplementaryFilterBankChannelAnalyser channel = new ComplementaryFilterBankChannelAnalyser(N);
channel.apply(x);
DDSAudioInputStream outputAudio;
String outFileName;
// Lowpass output
AudioFormat loFormat = new AudioFormat(inputAudio.getFormat().getSampleRate() * 0.5f, inputAudio.getFormat()
.getSampleSizeInBits(), inputAudio.getFormat().getChannels(), true, true);
outputAudio = new DDSAudioInputStream(new BufferedDoubleDataSource(channel.lpfOut), loFormat);
outFileName = args[0].substring(0, args[0].length() - 4) + "_lo.wav";
AudioSystem.write(outputAudio, AudioFileFormat.Type.WAVE, new File(outFileName));
//
// Lowpass interpolated output
AudioFormat loiFormat = new AudioFormat(inputAudio.getFormat().getSampleRate(), inputAudio.getFormat()
.getSampleSizeInBits(), inputAudio.getFormat().getChannels(), true, true);
outputAudio = new DDSAudioInputStream(new BufferedDoubleDataSource(channel.lpfOutInterpolated), loiFormat);
outFileName = args[0].substring(0, args[0].length() - 4) + "_loi.wav";
AudioSystem.write(outputAudio, AudioFileFormat.Type.WAVE, new File(outFileName));
//
// Highpass output
outputAudio = new DDSAudioInputStream(new BufferedDoubleDataSource(channel.hpfOut), inputAudio.getFormat());
outFileName = args[0].substring(0, args[0].length() - 4) + "_hi.wav";
AudioSystem.write(outputAudio, AudioFileFormat.Type.WAVE, new File(outFileName));
//
}
}