plectrum

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

AMDF.java (4295B)


      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.pitch;
     25 
     26 /**
     27  * <p>
     28  * A pitch extractor that extracts the Average Magnitude Difference (AMDF) from
     29  * an audio buffer. This is a good measure of the Pitch (f0) of a signal.
     30  * </p>
     31  * <p>
     32  * AMDF is calculated by the the difference between the waveform summing a
     33  * lagged version of itself.
     34  * </p>
     35  * <p>
     36  * The main bulk of the code is written by Eder de Souza for the <a
     37  * href="http://jaudio.sf.net">jAudio</a> framework. Adapted for TarsosDSP by
     38  * Joren Six.
     39  * </p>
     40  * 
     41  * @author Eder Souza (ederwander on github)
     42  * @author Joren Six
     43  */
     44 public class AMDF implements PitchDetector{
     45 	
     46 	
     47 	private static final double DEFAULT_MIN_FREQUENCY = 82.0;
     48 	private static final double DEFAULT_MAX_FREQUENCY = 1000.0;
     49 	private static final double DEFAULT_RATIO = 5.0;
     50 	private static final double DEFAULT_SENSITIVITY = 0.1;
     51 	
     52 	private final float sampleRate;
     53 	
     54 	private final double[] amd;
     55 	private final long maxPeriod;
     56 	private final long minPeriod;	
     57 	private final double ratio;
     58 	private final double sensitivity;
     59 	
     60 	/**
     61 	 * The result of the pitch detection iteration.
     62 	 */
     63 	private final PitchDetectionResult result;
     64 
     65 	public AMDF(float sampleRate, int bufferSize) {
     66 		this(sampleRate,bufferSize,DEFAULT_MIN_FREQUENCY,DEFAULT_MAX_FREQUENCY);
     67 	}
     68 	
     69 	public AMDF(float sampleRate, int bufferSize,double minFrequency,double maxFrequency) {
     70 		this.sampleRate = sampleRate;
     71 		amd = new double[bufferSize];
     72 		this.ratio = DEFAULT_RATIO;
     73 		this.sensitivity = DEFAULT_SENSITIVITY;
     74 		this.maxPeriod = Math.round(sampleRate / minFrequency + 0.5);
     75 		this.minPeriod = Math.round(sampleRate / maxFrequency + 0.5);
     76 		result = new PitchDetectionResult();
     77 	}
     78 
     79 	@Override
     80 	public PitchDetectionResult getPitch(float[] audioBuffer) {
     81 		int t = 0;
     82 		float f0 = -1;
     83 		double minval = Double.POSITIVE_INFINITY;
     84 		double maxval = Double.NEGATIVE_INFINITY;
     85 		double[] frames1 = new double[0];
     86 		double[] frames2 = new double[0];
     87 		double[] calcSub = new double[0];
     88 
     89 		int maxShift = audioBuffer.length;
     90 		
     91 
     92 		for (int i = 0; i < maxShift; i++) {
     93 			frames1 = new double[maxShift - i + 1];
     94 			frames2 = new double[maxShift - i + 1];
     95 			t = 0;
     96 			for (int aux1 = 0; aux1 < maxShift - i; aux1++) {
     97 				t = t + 1;
     98 				frames1[t] = audioBuffer[aux1];
     99 
    100 			}
    101 			t = 0;
    102 			for (int aux2 = i; aux2 < maxShift; aux2++) {
    103 				t = t + 1;
    104 				frames2[t] = audioBuffer[aux2];
    105 			}
    106 
    107 			int frameLength = frames1.length;
    108 			calcSub = new double[frameLength];
    109 			for (int u = 0; u < frameLength; u++) {
    110 				calcSub[u] = frames1[u] - frames2[u];
    111 			}
    112 
    113 			double summation = 0;
    114 			for (int l = 0; l < frameLength; l++) {
    115 				summation +=  Math.abs(calcSub[l]);
    116 			}
    117 			amd[i] = summation;
    118 		}
    119 		
    120 		for (int j = (int)minPeriod; j < (int)maxPeriod; j++){
    121 			if(amd[j] < minval){
    122 				 minval = amd[j];
    123 			}
    124 			if(amd[j] > maxval)	{
    125 				 maxval = amd[j];
    126 			}
    127 		}
    128 		int cutoff = (int) Math.round((sensitivity * (maxval - minval)) + minval);
    129 		int j=(int)minPeriod;
    130 		
    131 		while(j<=(int)maxPeriod && (amd[j] > cutoff)){
    132 			j=j+1;
    133 		}
    134 		
    135 		double search_length = minPeriod / 2;
    136 		minval = amd[j];
    137 		int minpos = j;
    138 		int i=j;
    139 		while((i<j+search_length) && (i<=maxPeriod)){
    140 			i=i+1;
    141 			if(amd[i] < minval){
    142 		          minval = amd[i];
    143 		          minpos = i;
    144 			}
    145 		}
    146 
    147 		if(Math.round(amd[minpos] * ratio) < maxval){
    148 			f0 = sampleRate/minpos;
    149 		}
    150 		
    151 		result.setPitch(f0);
    152 		result.setPitched(-1!=f0);
    153 		result.setProbability(-1);
    154 
    155 		return result;
    156 	}	
    157 }