/* * _______ _____ _____ _____ * |__ __| | __ \ / ____| __ \ * | | __ _ _ __ ___ ___ ___| | | | (___ | |__) | * | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/ * | | (_| | | \__ \ (_) \__ \ |__| |____) | | * |_|\__,_|_| |___/\___/|___/_____/|_____/|_| * * ------------------------------------------------------------- * * 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.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; import be.tarsos.dsp.AudioDispatcher; import be.tarsos.dsp.AudioEvent; import be.tarsos.dsp.AudioProcessor; import be.tarsos.dsp.SilenceDetector; import be.tarsos.dsp.beatroot.BeatRootOnsetEventHandler; import be.tarsos.dsp.io.jvm.AudioDispatcherFactory; import be.tarsos.dsp.onsets.ComplexOnsetDetector; import be.tarsos.dsp.onsets.OnsetHandler; import be.tarsos.dsp.pitch.PitchDetectionHandler; import be.tarsos.dsp.pitch.PitchDetectionResult; import be.tarsos.dsp.pitch.PitchProcessor; import be.tarsos.dsp.pitch.PitchProcessor.PitchEstimationAlgorithm; /** * Provides support for different types of command LineWavelet audio feature extraction. * @author Joren Six */ public class FeatureExtractor { private final List<FeatureExtractorApp> featureExtractors; public FeatureExtractor(String...arguments){ //Create a list of feature extractors featureExtractors = new ArrayList<FeatureExtractorApp>(); featureExtractors.add(new SoundPressureLevelExtractor()); featureExtractors.add(new PitchExtractor()); featureExtractors.add(new RootMeanSquareExtractor()); featureExtractors.add(new OnsetExtractor()); featureExtractors.add(new BeatExtractor()); checkArgumentsAndRun(arguments); } private void checkArgumentsAndRun(String... arguments){ if(arguments.length == 0){ printError(); } else { String subCommand = arguments[0].toLowerCase(); FeatureExtractorApp appToExecute = null; for(FeatureExtractorApp app : featureExtractors){ if(subCommand.equalsIgnoreCase(app.name())){ appToExecute = app; } } if(appToExecute == null){ printError(); }else{ try { if(!appToExecute.run(arguments)){ printHelp(appToExecute); } } catch (UnsupportedAudioFileException e) { printHelp(appToExecute); SharedCommandLineUtilities.printLine(); System.err.println("Error:"); System.err.println("\tThe audio file is not supported!"); } catch (IOException e) { printHelp(appToExecute); SharedCommandLineUtilities.printLine(); System.err.println("Current error:"); System.err.println("\tIO error, maybe the audio file is not found or not supported!"); } } } } private final void printError(){ SharedCommandLineUtilities.printPrefix(); System.err.println("Name:"); System.err.println("\tTarsosDSP feature extractor"); SharedCommandLineUtilities.printLine(); System.err.println("Synopsis:"); System.err.println("\tjava -jar FeatureExtractor.jar SUB_COMMAND [options...]"); SharedCommandLineUtilities.printLine(); System.err.println("Description:"); System.err.println("\t Extracts features from an audio file, SUB_COMMAND needs\n\tto be one of the following:"); for (FeatureExtractorApp app : featureExtractors) { System.err.println("\t\t" + app.name()); } } private final void printHelp(FeatureExtractorApp appToExecute){ SharedCommandLineUtilities.printPrefix(); System.err.println("Name:"); System.err.println("\tTarsosDSP " + appToExecute.name() + " feature extractor"); SharedCommandLineUtilities.printLine(); System.err.println("Synopsis:"); System.err.println("\tjava -jar FeatureExtractor.jar " + appToExecute.name() + " " + appToExecute.synopsis()); SharedCommandLineUtilities.printLine(); System.err.println("Description:"); System.err.println(appToExecute.description()); } /** * @param arguments */ public static void main(String... arguments) { new FeatureExtractor(arguments); } private interface FeatureExtractorApp{ String name(); String description(); String synopsis(); boolean run(String... args) throws UnsupportedAudioFileException, IOException; } private class RootMeanSquareExtractor implements FeatureExtractorApp{ @Override public String name() { return "rms"; } @Override public String description() { return "\tCalculates the root mean square of an audio signal for each \n\tblock of 2048 samples. The output gives you a timestamp and the RMS value,\n\tSeparated by a semicolon.\n\n\t\n\ninput.wav: a\treadable audio file."; } @Override public String synopsis() { return "input.wav"; } @Override public boolean run(String... args) throws UnsupportedAudioFileException, IOException { if(args.length!=2){ return false; } String inputFile = args[1]; File audioFile = new File(inputFile); int size = 2048; int overlap = 0; AudioDispatcher dispatcher = AudioDispatcherFactory.fromFile(audioFile, size, overlap); dispatcher.addAudioProcessor(new AudioProcessor() { @Override public void processingFinished() { } @Override public boolean process(AudioEvent audioEvent) { System.out.println(audioEvent.getTimeStamp() + "," + audioEvent.getRMS()); return true; } }); dispatcher.run(); return true; } } private class SoundPressureLevelExtractor implements FeatureExtractorApp{ @Override public String name() { return "sound_pressure_level"; } @Override public String description() { return "\tCalculates a sound pressure level in dB for each\n\tblock of 2048 samples.The output gives you a timestamp and a value in dBSPL.\n\tSeparated by a semicolon.\n\n\t\n\nWith input.wav\ta readable audio file."; } @Override public String synopsis() { return "input.wav"; } @Override public boolean run(String... args) throws UnsupportedAudioFileException, IOException { if(args.length!=2){ return false; } String inputFile = args[1]; File audioFile = new File(inputFile); int size = 2048; int overlap = 0; final SilenceDetector silenceDetecor = new SilenceDetector(); AudioDispatcher dispatcher = AudioDispatcherFactory.fromFile(audioFile, size, overlap); dispatcher.addAudioProcessor(silenceDetecor); dispatcher.addAudioProcessor(new AudioProcessor() { @Override public void processingFinished() { } @Override public boolean process(AudioEvent audioEvent) { System.out.println(audioEvent.getTimeStamp() + "," + silenceDetecor.currentSPL()); return true; } }); dispatcher.run(); return true; } } private class PitchExtractor implements FeatureExtractorApp, PitchDetectionHandler{ @Override public String name() { return "pitch"; } @Override public String description() { String descr = "\tCalculates pitch in Hz for each block of 2048 samples. \n\tThe output is a semicolon separated list of a timestamp, frequency in hertz and \n\ta probability which describes how pitched the sound is at the given time. "; descr += "\n\n\tinput.wav\t\ta readable wav file."; 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"; } return descr; } @Override public String synopsis() { String helpString = "[--detector DETECTOR] input.wav"; return helpString; } @Override public boolean run(String... args) throws UnsupportedAudioFileException, IOException { PitchEstimationAlgorithm algo = PitchEstimationAlgorithm.FFT_YIN; String inputFile = args[1]; if(args.length == 1 || args.length == 3){ return false; }else if(args.length==4 && !args[1].equalsIgnoreCase("--detector")){ return false; }else if(args.length==4 && args[1].equalsIgnoreCase("--detector")){ try{ algo = PitchEstimationAlgorithm.valueOf(args[2].toUpperCase()); inputFile = args[3]; }catch(IllegalArgumentException e){ //if enum value string is not recognized return false; } } File audioFile = new File(inputFile); float samplerate = AudioSystem.getAudioFileFormat(audioFile).getFormat().getSampleRate(); int size = 1024; int overlap = 0; AudioDispatcher dispatcher = AudioDispatcherFactory.fromFile(audioFile, size, overlap); dispatcher.addAudioProcessor(new PitchProcessor(algo, samplerate, size, this)); dispatcher.run(); return true; } @Override public void handlePitch(PitchDetectionResult pitchDetectionResult, AudioEvent audioEvent) { double timeStamp = audioEvent.getTimeStamp(); float pitch = pitchDetectionResult.getPitch(); float probability = pitchDetectionResult.getProbability(); System.out.println(timeStamp+","+pitch+","+probability); } } private class OnsetExtractor implements FeatureExtractorApp, OnsetHandler{ @Override public String name() { return "onset"; } @Override public String description() { String descr = "\tCalculates onsets using a complex domain onset detector. " + "\n\tThe output is a semicolon separated list of a timestamp, and a salliance. "; descr += "\n\n\tinput.wav\t\ta readable wav file."; descr += ""; return descr; } @Override public String synopsis() { String helpString = "input.wav"; return helpString; } @Override public boolean run(String... args) throws UnsupportedAudioFileException, IOException { String inputFile = args[1]; File audioFile = new File(inputFile); int size = 512; int overlap = 256; AudioDispatcher dispatcher = AudioDispatcherFactory.fromPipe(audioFile.getAbsolutePath(),44100, size, overlap); ComplexOnsetDetector detector = new ComplexOnsetDetector(size,0.7,0.1); detector.setHandler(this); dispatcher.addAudioProcessor(detector); dispatcher.run(); return true; } @Override public void handleOnset(double time, double salience) { System.out.println(time + "," + salience); } } private class BeatExtractor implements FeatureExtractorApp, OnsetHandler{ @Override public String name() { return "beat"; } @Override public String description() { String descr = "\tCalculates onsets using a complex domain onset detector. " + "\n\tThe output is a semicolon separated list of a timestamp, and a salliance. "; descr += "\n\n\tinput.wav\t\ta readable wav file."; descr += ""; return descr; } @Override public String synopsis() { String helpString = "input.wav"; return helpString; } @Override public boolean run(String... args) throws UnsupportedAudioFileException, IOException { String inputFile = args[1]; File audioFile = new File(inputFile); int size = 512; int overlap = 256; AudioDispatcher dispatcher = AudioDispatcherFactory.fromFile(audioFile, size, overlap); ComplexOnsetDetector detector = new ComplexOnsetDetector(size); BeatRootOnsetEventHandler handler = new BeatRootOnsetEventHandler(); detector.setHandler(handler); dispatcher.addAudioProcessor(detector); dispatcher.run(); handler.trackBeats(this); return true; } @Override public void handleOnset(double time, double salience) { System.out.println(time); } } }