plectrum

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

FFT.java (6946B)


      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.util.fft;
     26 
     27 
     28 /**
     29  * Wrapper for calling a hopefully Fast Fourier transform. Makes it easy to
     30  * switch FFT algorithm with minimal overhead.
     31  * Support for window functions is also present.
     32  * 
     33  * @author Joren Six
     34  */
     35 public class FFT {
     36 
     37 	/**
     38 	 * Forward FFT.
     39 	 */
     40 	private final FloatFFT fft;
     41 	private final WindowFunction windowFunction;
     42 	private final int fftSize;
     43 	private final float[] window; 
     44 
     45 	public FFT(final int size) {
     46 		this(size,null);
     47 	}
     48 	
     49 
     50 	
     51 	/**
     52 	 * Create a new fft of the specified size. Apply the specified window on the samples before a forward transform. 
     53 	 * arning: the window is not applied in reverse when a backwards transform is requested.
     54 	 * @param size The size of the fft.
     55 	 * @param windowFunction Apply the specified window on the samples before a forward transform. 
     56 	 * arning: the window is not applied in reverse when a backwards transform is requested.
     57 	 */
     58 	public FFT(final int size, final WindowFunction windowFunction){
     59 		fft = new FloatFFT(size);
     60 		fftSize = size;
     61 		this.windowFunction = windowFunction;
     62 		if(windowFunction==null)
     63 			window = null;
     64 		else
     65 		   window = windowFunction.generateCurve(size);
     66 	}
     67 
     68 	/**
     69 	 * Computes forward DFT.
     70 	 * 
     71 	 * @param data
     72 	 *            data to transform.
     73 	 */
     74 	public void forwardTransform(final float[] data) {
     75 		if(windowFunction!=null){
     76 			for(int i = 0 ; i < data.length ; i++){
     77 				data[i] = data[i] * window[i];
     78 			}
     79 			//windowFunction.apply(data);
     80 		}
     81 		fft.realForward(data);
     82 	}
     83 	
     84 	public void complexForwardTransform(final float[] data) {
     85 		if(windowFunction!=null){
     86 			for(int i = 0 ; i < data.length ; i++){
     87 				data[i] = data[i] * window[i];
     88 			}
     89 			//windowFunction.apply(data);
     90 		}
     91 		fft.complexForward(data);
     92 	}
     93 
     94 	/**
     95 	 * Computes inverse DFT.
     96 	 * Warning, does not reverse the window function.
     97 	 * @param data
     98 	 *            data to transform
     99 	 */
    100 	public void backwardsTransform(final float[] data) {
    101 		fft.realInverse(data, true);
    102 	}
    103 
    104 	public double binToHz(final int binIndex, final float sampleRate) {
    105 		return binIndex * sampleRate / (double) fftSize;
    106 	}
    107 	
    108 	public int size(){
    109 		return fftSize;
    110 	}
    111 
    112 	/**
    113 	 * Returns the modulus of the element at index bufferCount. The modulus,
    114 	 * magnitude or absolute value is (a²+b²) ^ 0.5 with a being the real part
    115 	 * and b the imaginary part of a complex number.
    116 	 * 
    117 	 * @param data
    118 	 *            The FFT transformed data.
    119 	 * @param index
    120 	 *            The index of the element.
    121 	 * @return The modulus, magnitude or absolute value of the element at index
    122 	 *         bufferCount
    123 	 */
    124 	public float modulus(final float[] data, final int index) {
    125 		final int realIndex = 2 * index;
    126 		final int imgIndex =  2 * index + 1;
    127 		final float modulus = data[realIndex] * data[realIndex] + data[imgIndex] * data[imgIndex];
    128 		return (float) Math.sqrt(modulus);
    129 	}
    130 
    131 	/**
    132 	 * Calculates the the modulus for each element in data and stores the result
    133 	 * in amplitudes.
    134 	 * 
    135 	 * @param data
    136 	 *            The input data.
    137 	 * @param amplitudes
    138 	 *            The output modulus info or amplitude.
    139 	 */
    140 	public void modulus(final float[] data, final float[] amplitudes) {
    141 		assert data.length / 2 == amplitudes.length;
    142 		for (int i = 0; i < amplitudes.length; i++) {
    143 			amplitudes[i] = modulus(data, i);
    144 		}
    145 	}
    146 	
    147 	/**
    148 	 * Computes an FFT and converts the results to polar coordinates (power and
    149 	 * phase). Both the power and phase arrays must be the same length, data
    150 	 * should be double the length.
    151 	 * 
    152 	 * @param data
    153 	 *            The input audio signal.
    154 	 * @param power
    155 	 *            The power (modulus) of the data.
    156 	 * @param phase
    157 	 *            The phase of the data
    158 	 */
    159 	public void powerPhaseFFT(float[] data,float[] power, float[] phase) {
    160 		assert data.length / 2 == power.length;
    161 		assert data.length / 2 == phase.length;
    162 		if(windowFunction!=null){
    163 			windowFunction.apply(data);
    164 		}
    165 		fft.realForward(data);
    166 		powerAndPhaseFromFFT(data, power, phase);
    167 	}
    168 	
    169 	
    170 	/**
    171 	 * Returns magnitude (or power) and phase for the FFT transformed data. 
    172 	 * @param data The FFT transformed data.
    173 	 * @param power The array where the magnitudes or powers are going to be stored. It is half the length of data (FFT size).
    174 	 * @param phase The array where the phases are going to be stored. It is half the length of data (FFT size).
    175 	 */
    176 	public void powerAndPhaseFromFFT(float[] data,float[] power, float[] phase){
    177 		phase[0] = (float) Math.PI;
    178 		power[0] = -data[0];
    179 		for (int i = 1; i < power.length; i++) {
    180 			int realIndex = 2 * i;
    181 			int imgIndex  = 2 * i + 1;
    182 			power[i] = (float) Math.sqrt(data[realIndex] * data[realIndex] + data[imgIndex] * data[imgIndex]);
    183 			phase[i] = (float) Math.atan2(data[imgIndex], data[realIndex]);
    184 		}
    185 	}
    186 	
    187 	public void powerPhaseFFTBeatRootOnset(float[] data,float[] power, float[] phase) {
    188 		powerPhaseFFT(data, power, phase);
    189 		power[0] = (float) Math.sqrt(data[0] * data[0] + data[1] * data[1]);
    190 	}
    191 	
    192 	/**
    193 	 * Multiplies to arrays containing imaginary numbers. The data in the first argument
    194 	 * is modified! The real part is stored at <code>2*i</code>, the imaginary part <code>2*i+i</code>
    195 	 * @param data The array with imaginary numbers that is modified.
    196 	 * @param other The array with imaginary numbers that is not modified.
    197 	 * Data and other need to be the same length.
    198 	 */
    199 	public void multiply(float[] data, float[] other){
    200 		assert data.length == other.length;
    201 		if(data.length!=other.length){
    202 			throw new IllegalArgumentException("Both arrays with imaginary numbers shouldb e of equal length");
    203 		}
    204 		for (int i = 1; i < data.length-1; i+=2) {
    205 			int realIndex = i;
    206 			int imgIndex = i + 1;
    207 			float tempReal = data[realIndex] * other[realIndex] + -1 * data[imgIndex] * other[imgIndex];
    208 			float tempImg = data[realIndex] * other[imgIndex] + data[imgIndex] * other[realIndex];
    209 			data[realIndex] = tempReal;
    210 			data[imgIndex] = tempImg;
    211 			//fix by perfecthu 
    212 			//data[realIndex] = data[realIndex] * other[realIndex] + -1 * data[imgIndex] * other[imgIndex];
    213 			//data[imgIndex] = data[realIndex] * other[imgIndex] + data[imgIndex] * other[realIndex];
    214 			}
    215 	}
    216 }