/** * Copyright 2004-2006 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.process; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; 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.DoubleDataSource; import marytts.util.data.MixerDoubleDataSource; import marytts.util.data.NoiseDoubleDataSource; import marytts.util.data.SequenceDoubleDataSource; import marytts.util.data.SilenceDoubleDataSource; import marytts.util.data.audio.AudioDoubleDataSource; import marytts.util.data.audio.DDSAudioInputStream; public class AudioFileMixer { public static void mixTwoFiles(String inputFile1, double mixAmount1, String inputFile2, double mixAmount2, String outputFile) throws UnsupportedAudioFileException, IOException { AudioInputStream inputAudio1 = AudioSystem.getAudioInputStream(new File(inputFile1)); int samplingRate1 = (int) inputAudio1.getFormat().getSampleRate(); AudioDoubleDataSource signal1 = new AudioDoubleDataSource(inputAudio1); double[] x1 = signal1.getAllData(); AudioInputStream inputAudio2 = AudioSystem.getAudioInputStream(new File(inputFile2)); int samplingRate2 = (int) inputAudio1.getFormat().getSampleRate(); AudioDoubleDataSource signal2 = new AudioDoubleDataSource(inputAudio2); double[] x2 = signal2.getAllData(); if (samplingRate1 != samplingRate2) System.out.println("Error! Sampling rates must be identical for mixing..."); else { int i; double[] x3 = new double[Math.max(x1.length, x2.length)]; if (x1.length > x2.length) { for (i = 0; i < x2.length; i++) x3[i] = mixAmount1 * x1[i] + mixAmount2 * x2[i]; for (i = x2.length; i < x3.length; i++) x3[i] = mixAmount1 * x1[i]; } else { for (i = 0; i < x1.length; i++) x3[i] = mixAmount1 * x1[i] + mixAmount2 * x2[i]; for (i = x1.length; i < x3.length; i++) x3[i] = mixAmount2 * x2[i]; } DDSAudioInputStream outputAudio = new DDSAudioInputStream(new BufferedDoubleDataSource(x3), inputAudio1.getFormat()); AudioSystem.write(outputAudio, AudioFileFormat.Type.WAVE, new File(outputFile)); } } /** * Mix a number of audio files to each of a set of audio files, normalizing these audio files to the average power of the * reference audio files. * * @param args * args * @throws Exception * Exception */ public static void main(String[] args) throws Exception { if (true) { List audio = new ArrayList(); // to play in parallel to each argument double[] audioData = null; List referenceAudio = new ArrayList(); // to normalise power List noiseSpecs = new ArrayList(); double maxDuration = 0; int i = 0; String prop; // The audio format of the first argument is the target format! AudioFormat format; if (args.length > 0) format = AudioSystem.getAudioInputStream(new File(args[0])).getFormat(); else format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 16000, // samples per second 16, // bits per sample 1, // mono 2, // nr. of bytes per frame 16000, // nr. of frames per second false // little-endian ); while (!(prop = System.getProperty("audio." + (++i), "")).equals("")) { DoubleDataSource dds = null; if (prop.startsWith("noise:")) { noiseSpecs.add(prop); } else { String[] info = prop.split(":"); String filename = info[info.length - 1]; double start = 0; if (info.length > 1) start = Double.valueOf(info[0]).doubleValue(); AudioInputStream ais = AudioSystem.getAudioInputStream(new File(filename)); if (!format.equals(ais.getFormat())) // convert to target format ais = AudioSystem.getAudioInputStream(format, ais); double[] signal = new AudioDoubleDataSource(ais).getAllData(); double duration = signal.length / format.getSampleRate(); if (duration > maxDuration) maxDuration = duration; referenceAudio.add(new BufferedDoubleDataSource(signal)); dds = new BufferedDoubleDataSource(signal); if (start > 0) dds = new SequenceDoubleDataSource(new DoubleDataSource[] { new SilenceDoubleDataSource((long) (start * format.getSampleRate())), dds }); audio.add(dds); } } EnergyNormaliser powerNormaliser = null; if (referenceAudio.size() > 0) { powerNormaliser = new EnergyNormaliser(new SequenceDoubleDataSource(referenceAudio)); System.err.println("Reference power: " + powerNormaliser.getReferencePower()); } for (Iterator it = noiseSpecs.iterator(); it.hasNext();) { String spec = (String) it.next(); String[] info = spec.split(":"); double start = 0; if (info.length > 2) start = Double.valueOf(info[1]).doubleValue(); double duration = maxDuration - start; if (info.length > 3) duration = Double.valueOf(info[2]).doubleValue(); double db = Double.valueOf(info[info.length - 1]).doubleValue(); DoubleDataSource noise = new NoiseDoubleDataSource((long) (duration * format.getSampleRate()), db); if (start > 0) noise = new SequenceDoubleDataSource(new DoubleDataSource[] { new SilenceDoubleDataSource((long) (start * format.getSampleRate())), noise }); audio.add(noise); } if (audio.size() > 0) audioData = new MixerDoubleDataSource(audio).getAllData(); // If no arguments are present: if (args.length == 0) { AudioInputStream audioStream = new DDSAudioInputStream(new BufferedDoubleDataSource(audioData), format); String prefix = System.getProperty("prefix", "mixed_"); File outFile = new File(prefix + ".wav"); // in the current directory AudioSystem.write(audioStream, AudioFileFormat.Type.WAVE, outFile); System.out.println("Wrote " + outFile.getPath()); System.exit(0); } // How to time the audio given as the arguments: double argsStart = Double.valueOf(System.getProperty("audio.args", "0")).doubleValue(); for (int k = 0; k < args.length; k++) { List result = new ArrayList(); if (audioData != null) { result.add(new BufferedDoubleDataSource(audioData)); } File inFile = new File(args[k]); AudioInputStream ais = AudioSystem.getAudioInputStream(inFile); if (!format.equals(ais.getFormat())) ais = AudioSystem.getAudioInputStream(format, ais); DoubleDataSource dds = new AudioDoubleDataSource(ais); if (powerNormaliser != null) dds = powerNormaliser.apply(dds); if (argsStart > 0) { dds = new SequenceDoubleDataSource(new DoubleDataSource[] { new SilenceDoubleDataSource((long) (argsStart * format.getSampleRate())), dds }); } result.add(dds); DoubleDataSource resultDDS = new MixerDoubleDataSource(result); AudioInputStream resultStream = new DDSAudioInputStream(resultDDS, format); String prefix = System.getProperty("prefix", "mixed_"); String filename = inFile.getName(); filename = prefix + filename.substring(0, filename.lastIndexOf('.')) + ".wav"; File outFile = new File(filename); // in the current directory AudioSystem.write(resultStream, AudioFileFormat.Type.WAVE, outFile); System.out.println("Wrote " + outFile.getPath()); } } else // Simple mixing of two files { mixTwoFiles("d:/1_2klpf_sinTScaled.wav", 1.0, "d:/1_2khpf.wav", 1.0, "d:/1_merged.wav"); } } }