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 }