plectrum

Plectrum: instrument tuner for Android
Log | Files | Refs | README | LICENSE

PitchResyntheziser.java (4504B)


      1 /*
      2 *      _______                       _____   _____ _____  
      3 *     |__   __|                     |  __ \ / ____|  __ \ 
      4 *        | | __ _ _ __ ___  ___  ___| |  | | (___ | |__) |
      5 *        | |/ _` | '__/ __|/ _ \/ __| |  | |\___ \|  ___/ 
      6 *        | | (_| | |  \__ \ (_) \__ \ |__| |____) | |     
      7 *        |_|\__,_|_|  |___/\___/|___/_____/|_____/|_|     
      8 *                                                         
      9 * -------------------------------------------------------------
     10 *
     11 * TarsosDSP is developed by Joren Six at IPEM, University Ghent
     12 *  
     13 * -------------------------------------------------------------
     14 *
     15 *  Info: http://0110.be/tag/TarsosDSP
     16 *  Github: https://github.com/JorenSix/TarsosDSP
     17 *  Releases: http://0110.be/releases/TarsosDSP/
     18 *  
     19 *  TarsosDSP includes modified source code by various authors,
     20 *  for credits and info, see README.
     21 * 
     22 */
     23 
     24 package be.tarsos.dsp.synthesis;
     25 
     26 import java.util.Arrays;
     27 
     28 import be.tarsos.dsp.AudioEvent;
     29 import be.tarsos.dsp.EnvelopeFollower;
     30 import be.tarsos.dsp.pitch.PitchDetectionHandler;
     31 import be.tarsos.dsp.pitch.PitchDetectionResult;
     32 
     33 /**
     34  * This pitch detection handler replaces the audio buffer in the pipeline with a
     35  * synthesized wave. It either follows the envelope of the original signal or
     36  * not. Use it wisely. The following demonstrates how it can be used.
     37  * 
     38  * <pre>
     39  * <code>
     40  * PitchEstimationAlgorithm algo = PitchEstimationAlgorithm.FFT_YIN;
     41  * PitchResyntheziser prs = new PitchResyntheziser(samplerate);
     42  * AudioDispatcher dispatcher = AudioDispatcher.fromFile(new File("in.wav"),1024, 0);
     43  * //Handle pitch detection
     44  * dispatcher.addAudioProcessor(new PitchProcessor(algo, samplerate, size, prs));
     45  * //Write the synthesized pitch to an output file.
     46  * dispatcher.addAudioProcessor(new WaveformWriter(format, "out.wav"));//
     47  * dispatcher.run();
     48  * </code>
     49  * </pre>
     50  * 
     51  * @author Joren Six
     52  */
     53 public class PitchResyntheziser implements PitchDetectionHandler {
     54 
     55 	private double phase = 0;
     56 	private double phaseFirst = 0;
     57 	private double phaseSecond = 0;
     58 	private double prevFrequency = 0;
     59 	private float samplerate;
     60 	private final EnvelopeFollower envelopeFollower;
     61 	private boolean usePureSine;
     62 	private boolean followEnvelope;
     63 	private final double[] previousFrequencies;
     64 	private int previousFrequencyIndex;
     65 	
     66 	public PitchResyntheziser(float samplerate){
     67 		this(samplerate,true,false);
     68 	}
     69 	
     70 	public PitchResyntheziser(float samplerate,boolean followEnvelope,boolean pureSine){
     71 		this(samplerate,followEnvelope,pureSine,5);
     72 	}
     73 	
     74 	public PitchResyntheziser(float samplerate,boolean followEnvelope,boolean pureSine,int filterSize){
     75 		envelopeFollower = new EnvelopeFollower(samplerate,0.005,0.01);
     76 		this.followEnvelope=followEnvelope;
     77 		this.usePureSine = pureSine;
     78 		this.samplerate = samplerate;
     79 		previousFrequencies = new double[filterSize];
     80 		previousFrequencyIndex = 0;
     81 	}
     82 	
     83 	@Override
     84 	public void handlePitch(PitchDetectionResult pitchDetectionResult,
     85 			AudioEvent audioEvent) {
     86 		double frequency = pitchDetectionResult.getPitch();
     87 		
     88 		if(frequency==-1){
     89 			frequency=prevFrequency;
     90 		}else{
     91 			if(previousFrequencies.length!=0){
     92 				//median filter
     93 				//store and adjust pointer
     94 				previousFrequencies[previousFrequencyIndex] = frequency;
     95 				previousFrequencyIndex++;
     96 				previousFrequencyIndex %= previousFrequencies.length;
     97 				//sort to get median frequency
     98 				double[] frequenciesCopy = previousFrequencies.clone();
     99 				Arrays.sort(frequenciesCopy);
    100 				//use the median as frequency
    101 				frequency = frequenciesCopy[frequenciesCopy.length/2];
    102 			}
    103 			
    104 			prevFrequency = frequency;
    105 		}
    106 		
    107 		
    108 	
    109 		final double twoPiF = 2 * Math.PI * frequency;
    110 		float[] audioBuffer = audioEvent.getFloatBuffer();
    111 		float[] envelope = null;
    112 		if(followEnvelope){
    113 			envelope = audioBuffer.clone();
    114 			envelopeFollower.calculateEnvelope(envelope);
    115 		}
    116 		
    117 		for (int sample = 0; sample < audioBuffer.length; sample++) {
    118 			double time =   sample / samplerate;
    119 			double wave =  Math.sin(twoPiF * time + phase);
    120 			if(!usePureSine){
    121 				wave += 0.05 * Math.sin(twoPiF * 4 * time + phaseFirst);
    122 				wave += 0.01 * Math.sin(twoPiF * 8 * time + phaseSecond);
    123 			}			
    124 			audioBuffer[sample] = (float) wave;
    125 			if(followEnvelope){
    126 				audioBuffer[sample] = audioBuffer[sample] * envelope[sample];
    127 			}
    128 		}
    129 		
    130 		double timefactor = twoPiF * audioBuffer.length / samplerate; 
    131 		phase =  timefactor + phase;
    132 		if(!usePureSine){
    133 			phaseFirst = 4 * timefactor + phaseFirst;
    134 			phaseSecond = 8 * timefactor + phaseSecond;
    135 		}
    136 	}
    137 }