All Downloads are FREE. Search and download functionalities are using the official Maven repository.

examples.be.tarsos.dsp.example.Resynthesizer Maven / Gradle / Ivy

The newest version!
/*
*      _______                       _____   _____ _____  
*     |__   __|                     |  __ \ / ____|  __ \ 
*        | | __ _ _ __ ___  ___  ___| |  | | (___ | |__) |
*        | |/ _` | '__/ __|/ _ \/ __| |  | |\___ \|  ___/ 
*        | | (_| | |  \__ \ (_) \__ \ |__| |____) | |     
*        |_|\__,_|_|  |___/\___/|___/_____/|_____/|_|     
*                                                         
* -------------------------------------------------------------
*
* TarsosDSP is developed by Joren Six at IPEM, University Ghent
*  
* -------------------------------------------------------------
*
*  Info: http://0110.be/tag/TarsosDSP
*  Github: https://github.com/JorenSix/TarsosDSP
*  Releases: http://0110.be/releases/TarsosDSP/
*  
*  TarsosDSP includes modified source code by various authors,
*  for credits and info, see README.
* 
*/

package be.tarsos.dsp.example;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.AudioEvent;
import be.tarsos.dsp.AudioProcessor;
import be.tarsos.dsp.GainProcessor;
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
import be.tarsos.dsp.io.jvm.AudioPlayer;
import be.tarsos.dsp.io.jvm.WaveformWriter;
import be.tarsos.dsp.pitch.PitchProcessor;
import be.tarsos.dsp.pitch.PitchProcessor.PitchEstimationAlgorithm;
import be.tarsos.dsp.synthesis.PitchResyntheziser;

/**
 * The resynthesizer example shows how to use the PitchResnthesizer class. It is
 * an application that extracts pitch from an audio file and resynthesizes it
 * using the envelope of the original signal and the pitch information. It can
 * be used to check pitch detection results.
 * 
 * @author Joren Six
 * 
 */

public class Resynthesizer{

	/**
	 * @param arguments
	 * @throws InterruptedException 
	 * @throws InvocationTargetException 
	 */
	public static void main(String... arguments) throws InterruptedException, InvocationTargetException {
		if(arguments.length==0){
			SwingUtilities.invokeAndWait(new Runnable() {
				@Override
				public void run() {
					try {
						UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
					} catch (Exception e) {
						//ignore failure to set default look en feel;
					}
					JFrame frame = new GraphicalResynthesizer();
					frame.pack();
					frame.setSize(400,350);
					frame.setVisible(true);
				}
			});
		}else{
			new CommandLineResynthesizer(arguments);
		}
	}
	
	private static class GraphicalResynthesizer extends JFrame{

		/**
		 * 
		 */
		private static final long serialVersionUID = 401554060116566946L;
		private final JSlider estimationGainSlider;
		private final JSlider sourceGainSlider;
		private AudioDispatcher estimationDispatcher;
		private AudioDispatcher sourceDispatcher;
		private GainProcessor estimationGain;
		private GainProcessor sourceGain;
		private final JFileChooser fileChooser;
		PitchEstimationAlgorithm algo;
		File currentFile;
		
		private ActionListener algoChangeListener = new ActionListener(){
			@Override
			public void actionPerformed(final ActionEvent e) {
				String name = e.getActionCommand();
				PitchEstimationAlgorithm newAlgo = PitchEstimationAlgorithm.valueOf(name);
				algo = newAlgo;
				if(currentFile!=null ){
					estimationDispatcher.stop();
					sourceDispatcher.stop();
					startFile(currentFile);
				}
				
		}};
		
		public GraphicalResynthesizer(){
			this.setLayout(new BorderLayout());
			this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			this.setTitle("Pitch Estimation Synthesizer");
			
			estimationGainSlider = new JSlider(0,200);
			estimationGainSlider.setValue(100);
			estimationGainSlider.setPaintLabels(true);
			estimationGainSlider.addChangeListener(new ChangeListener() {
				@Override
				public void stateChanged(ChangeEvent arg0) {
					if (GraphicalResynthesizer.this.estimationDispatcher != null) {
						double gainValue = estimationGainSlider.getValue() / 100.0;
						estimationGain.setGain(gainValue);
					}
				}
			});
			
			sourceGainSlider = new JSlider(0,200);
			sourceGainSlider.setValue(100);
			sourceGainSlider.setPaintLabels(true);
			sourceGainSlider.addChangeListener(new ChangeListener() {
				@Override
				public void stateChanged(ChangeEvent arg0) {
					if (GraphicalResynthesizer.this.sourceDispatcher != null) {
						double gainValue = sourceGainSlider.getValue() / 100.0;
						sourceGain.setGain(gainValue);
					}
				}
			});
			
			JPanel fileChooserPanel = new JPanel(new BorderLayout());
			fileChooserPanel.setBorder(new TitledBorder("1. Choose your audio (wav mono)"));
			
			fileChooser = new JFileChooser();
			
			JButton chooseFileButton = new JButton("Choose a file...");
			chooseFileButton.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent arg0) {
					int returnVal = fileChooser.showOpenDialog(GraphicalResynthesizer.this);
		            if (returnVal == JFileChooser.APPROVE_OPTION) {
		                File file = fileChooser.getSelectedFile();
		                startFile(file);
		            } else {
		                //canceled
		            }
				}			
			});
			fileChooserPanel.add(chooseFileButton,BorderLayout.CENTER);
			
			JPanel gainPanel = new JPanel(new GridLayout(2,2));
			JLabel label = new JLabel("Gain source (in %)");
			label.setToolTipText("Volume in % (100 is no change).");
			gainPanel.add(label);
			gainPanel.add(sourceGainSlider);
			label = new JLabel("Gain estimations (in %)");
			label.setToolTipText("Volume in % (100 is no change).");
			gainPanel.add(label);
			gainPanel.add(estimationGainSlider);
			gainPanel.setBorder(new TitledBorder("3. Change the estimation / source"));		
			this.add(fileChooserPanel,BorderLayout.NORTH);
			this.add(gainPanel,BorderLayout.SOUTH);
			JPanel pitchDetectionPanel = new PitchDetectionPanel(algoChangeListener);
			algo=PitchEstimationAlgorithm.YIN;
			this.add(pitchDetectionPanel,BorderLayout.CENTER);
		}



		protected void startFile(File file) {
			currentFile = file;
			AudioFormat format;
			try {
				format = AudioSystem.getAudioFileFormat(file).getFormat();
				float samplerate = format.getSampleRate();
				int size = 1024;
				int overlap = 0;
				
				PitchResyntheziser prs = new PitchResyntheziser(samplerate);
				estimationGain = new GainProcessor(estimationGainSlider.getValue()/100.0);
				estimationDispatcher = AudioDispatcherFactory.fromFile(file, size, overlap);
				estimationDispatcher.addAudioProcessor(new PitchProcessor(algo, samplerate, size, prs));
				estimationDispatcher.addAudioProcessor(estimationGain);
				estimationDispatcher.addAudioProcessor(new AudioPlayer(format));
				
				sourceGain = new GainProcessor(sourceGainSlider.getValue()/100.0);
				sourceDispatcher = AudioDispatcherFactory.fromFile(file, size, overlap);
				sourceDispatcher.addAudioProcessor(sourceGain);
				sourceDispatcher.addAudioProcessor(new AudioPlayer(format));
				
				new Thread(estimationDispatcher).start();
				new Thread(sourceDispatcher).start();
				
			} catch (UnsupportedAudioFileException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (LineUnavailableException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
	}
	
	private static class CommandLineResynthesizer {
		public CommandLineResynthesizer(String[] arguments) {
			checkArgumentsAndRun(arguments);
		}
		
		private void checkArgumentsAndRun(String... arguments){
			if(arguments.length == 0){
				printError();
			} else {
				try {
					run(arguments);
				} catch (UnsupportedAudioFileException e) {
					printError();
					SharedCommandLineUtilities.printLine();
					System.err.println("Error:");
					System.err.println("\tThe audio file is not supported!");
				} catch (IOException e) {
					printError();
					SharedCommandLineUtilities.printLine();
					System.err.println("Current error:");
					System.err.println("\tIO error, maybe the audio file is not found or not supported!");
				}
				catch (IllegalArgumentException e) {
						printError();
						SharedCommandLineUtilities.printLine();
						System.err.println("Current error:");
						System.err.println("\tThe algorithm provided is unknown!");
				} catch (LineUnavailableException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}	
			}
		}
		
		private void combineTwoMonoAudioFilesInTwoChannels(String first,String second,String outputFile) throws IOException, UnsupportedAudioFileException, LineUnavailableException{
			AudioInputStream stream = AudioSystem.getAudioInputStream(new File(first));
			final float sampleRate = (int) stream.getFormat().getSampleRate();
			final int numberOfSamples = (int) stream.getFrameLength();
			//2 bytes per sample, stereo (2 channels)
			final byte[] byteBuffer = new byte[numberOfSamples * 2 * 2]; 
			/*
			 * Read the source file data in the left channel
			 */
			stream = AudioSystem.getAudioInputStream(new File(first));
			byte[] sampleAsByteArray = new byte[2]; 
			for (int sample = 0; sample < numberOfSamples; sample++) {
				stream.read(sampleAsByteArray);
				byteBuffer[sample * 4 + 0] = sampleAsByteArray[0];
				byteBuffer[sample * 4 + 1] = sampleAsByteArray[1];
			}
			
			/*
			 * Read the source file data in the right channel
			 */
			stream = AudioSystem.getAudioInputStream(new File(second));
			sampleAsByteArray = new byte[2]; 
			for (int sample = 0; sample < numberOfSamples; sample++) {
				stream.read(sampleAsByteArray);
				byteBuffer[sample * 4 + 2] = sampleAsByteArray[0];
				byteBuffer[sample * 4 + 3] = sampleAsByteArray[1];
			}
			
			/*
			 * Write the data to a file.
			 */
			final AudioFormat audioFormat = new AudioFormat(sampleRate, 16, 2, true, false);
			final ByteArrayInputStream bais = new ByteArrayInputStream(byteBuffer);
			final AudioInputStream audioInputStream = new AudioInputStream(bais, audioFormat, numberOfSamples);
			final File out = new File(outputFile);
			AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, out);
			audioInputStream.close();
		}

		private void run(String[] args) throws UnsupportedAudioFileException, IOException, IllegalArgumentException, LineUnavailableException {
			PitchEstimationAlgorithm algo = PitchEstimationAlgorithm.FFT_YIN;
			String inputFile = args[0];
			String outputFile = null;
			String combinedFile = null;
			if(args.length == 3 && args[0].equalsIgnoreCase("--detector")){
				algo = PitchEstimationAlgorithm.valueOf(args[1].toUpperCase());
				inputFile = args[2];
			}else if(args.length == 3 && args[0].equalsIgnoreCase("--output")){
				outputFile = args[1];
				inputFile = args[2];
			}else if(args.length == 5 && args[0].equalsIgnoreCase("--detector") && args[2].equalsIgnoreCase("--output")){
				algo = PitchEstimationAlgorithm.valueOf(args[1].toUpperCase());
				outputFile = args[3];
				inputFile = args[4];
			}else if(args.length == 7 && args[0].equalsIgnoreCase("--detector") && args[2].equalsIgnoreCase("--output") && args[4].equalsIgnoreCase("--combined")){
				algo = PitchEstimationAlgorithm.valueOf(args[1].toUpperCase());
				outputFile = args[3];
				combinedFile = args[5];
				inputFile = args[6];
			} else if(args.length !=1){
				printError();
				SharedCommandLineUtilities.printLine();
				System.err.println("Current error:");
				System.err.println("\tThe command expects the options in the specified order, the current command is not parsed correctly!");
				return;
			}
			File audioFile = new File(inputFile);
			AudioFormat format = AudioSystem.getAudioFileFormat(audioFile).getFormat();
			float samplerate = format.getSampleRate();
			int size = 1024;
			int overlap = 0;
			PitchResyntheziser prs = new PitchResyntheziser(samplerate);
			AudioDispatcher dispatcher = AudioDispatcherFactory.fromFile(audioFile, size, overlap);
			dispatcher.addAudioProcessor(new PitchProcessor(algo, samplerate, size, prs));
			if(outputFile!=null){
				dispatcher.addAudioProcessor(new WaveformWriter(format, outputFile));
			}else{
				dispatcher.addAudioProcessor(new AudioPlayer(format));
			}
			dispatcher.addAudioProcessor(new AudioProcessor() {
				@Override
				public void processingFinished() {}
				
				@Override
				public boolean process(AudioEvent audioEvent) {
					System.err.print(String.format("%3.0f %%",audioEvent.getProgress() * 100));
					System.err.print(String.format("\b\b\b\b\b",audioEvent.getProgress()));
					return true;
				}
			});
			dispatcher.run();
			
			if(combinedFile!=null){
				combineTwoMonoAudioFilesInTwoChannels(inputFile, outputFile, combinedFile);
			}
		}

		private final void printError(){
			SharedCommandLineUtilities.printPrefix();
			System.err.println("Name:");
			System.err.println("\tTarsosDSP resynthesizer");
			SharedCommandLineUtilities.printLine();
			System.err.println("Synopsis:");
			System.err.println("\tjava -jar CommandLineResynthesizer.jar [--detector DETECTOR] [--output out.wav] [--combined combined.wav] input.wav");
			SharedCommandLineUtilities.printLine();
			System.err.println("Description:");
			System.err.println("\tExtracts pitch and loudnes from audio and resynthesises the audio with that information.\n\t" +
					"The result is either played back our written in an output file. \n\t" +
					"There is als an option to combine source and synthezized material\n\t" +
					"in the left and right channels of a stereo audio file.");
			String descr="";
			descr += "\n\n\tinput.wav\t\ta readable wav file.";
			descr += "\n\n\t--output out.wav\t\ta writable file.";
			descr += "\n\n\t--combined combined.wav\t\ta writable output file. One channel original, other synthesized.";
			descr += "\n\t--detector DETECTOR\tdefaults to FFT_YIN or one of these:\n\t\t\t\t";
			for(PitchEstimationAlgorithm algo : PitchEstimationAlgorithm.values()){
				descr += algo.name() + "\n\t\t\t\t";
			}
			System.err.println(descr);
	    }		
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy