Goertzel.java (4535B)
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 25 package be.tarsos.dsp.pitch; 26 27 import be.tarsos.dsp.AudioEvent; 28 import be.tarsos.dsp.AudioProcessor; 29 30 /** 31 * Contains an implementation of the Goertzel algorithm. It can be used to 32 * detect if one or more predefined frequencies are present in a signal. E.g. to 33 * do DTMF decoding. 34 * 35 * @author Joren Six 36 */ 37 public class Goertzel implements AudioProcessor { 38 39 /** 40 * If the power in dB is higher than this threshold, the frequency is 41 * present in the signal. 42 */ 43 private static final double POWER_THRESHOLD = 35;// in dB 44 45 /** 46 * A list of frequencies to detect. 47 */ 48 private final double[] frequenciesToDetect; 49 /** 50 * Cached cosine calculations for each frequency to detect. 51 */ 52 private final double[] precalculatedCosines; 53 /** 54 * Cached wnk calculations for each frequency to detect. 55 */ 56 private final double[] precalculatedWnk; 57 /** 58 * A calculated power for each frequency to detect. This array is reused for 59 * performance reasons. 60 */ 61 private final double[] calculatedPowers; 62 63 private final FrequenciesDetectedHandler handler; 64 65 public Goertzel(final float audioSampleRate, final int bufferSize, 66 double[] frequencies, FrequenciesDetectedHandler handler) { 67 68 frequenciesToDetect = frequencies; 69 precalculatedCosines = new double[frequencies.length]; 70 precalculatedWnk = new double[frequencies.length]; 71 this.handler = handler; 72 73 calculatedPowers = new double[frequencies.length]; 74 75 for (int i = 0; i < frequenciesToDetect.length; i++) { 76 precalculatedCosines[i] = 2 * Math.cos(2 * Math.PI 77 * frequenciesToDetect[i] / audioSampleRate); 78 precalculatedWnk[i] = Math.exp(-2 * Math.PI 79 * frequenciesToDetect[i] / audioSampleRate); 80 } 81 } 82 83 /** 84 * An interface used to react on detected frequencies. 85 * 86 * @author Joren Six 87 */ 88 public static interface FrequenciesDetectedHandler { 89 /** 90 * React on detected frequencies. 91 * 92 * @param frequencies 93 * A list of detected frequencies. 94 * @param powers 95 * A list of powers of the detected frequencies. 96 * @param allFrequencies 97 * A list of all frequencies that were checked. 98 * @param allPowers 99 * A list of powers of all frequencies that were checked. 100 */ 101 void handleDetectedFrequencies(final double timestamp,final double[] frequencies, 102 final double[] powers, final double[] allFrequencies, 103 final double allPowers[]); 104 } 105 106 @Override 107 public boolean process(AudioEvent audioEvent) { 108 float[] audioFloatBuffer = audioEvent.getFloatBuffer(); 109 double skn0, skn1, skn2; 110 int numberOfDetectedFrequencies = 0; 111 for (int j = 0; j < frequenciesToDetect.length; j++) { 112 skn0 = skn1 = skn2 = 0; 113 for (int i = 0; i < audioFloatBuffer.length; i++) { 114 skn2 = skn1; 115 skn1 = skn0; 116 skn0 = precalculatedCosines[j] * skn1 - skn2 117 + audioFloatBuffer[i]; 118 } 119 double wnk = precalculatedWnk[j]; 120 calculatedPowers[j] = 20 * Math.log10(Math.abs(skn0 - wnk * skn1)); 121 if (calculatedPowers[j] > POWER_THRESHOLD) { 122 numberOfDetectedFrequencies++; 123 } 124 } 125 126 if (numberOfDetectedFrequencies > 0) { 127 double[] frequencies = new double[numberOfDetectedFrequencies]; 128 double[] powers = new double[numberOfDetectedFrequencies]; 129 int index = 0; 130 for (int j = 0; j < frequenciesToDetect.length; j++) { 131 if (calculatedPowers[j] > POWER_THRESHOLD) { 132 frequencies[index] = frequenciesToDetect[j]; 133 powers[index] = calculatedPowers[j]; 134 index++; 135 } 136 } 137 handler.handleDetectedFrequencies(audioEvent.getTimeStamp(),frequencies, powers, 138 frequenciesToDetect.clone(), calculatedPowers.clone()); 139 } 140 141 return true; 142 } 143 144 145 146 @Override 147 public void processingFinished() { 148 } 149 150 }