/* Reversound is used to get the music sheet of a piece from a music file. Copyright (C) 2014 Gabriel AUGENDRE Copyright (C) 2014 Gabriel DIENY Copyright (C) 2014 Arthur GAUCHER Copyright (C) 2014 Gabriel LEPETIT-AIMON This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package generictools; import processing.buffer.Buffer; import java.util.ArrayList; /** * Created by Gabriel on 08/04/2014. * Contient les coefficients de la fenetre de pondération (masque à appliquer au signal) utilisée par la FFT. * Générée une unique fois pour un traitement de FFT. */ public class WindowFunction { private int startID; private final int width; private final Type windowType; private final Buffer temporalSignal; private ArrayList coef; private int divideFactor; // Caractérise la forme de la fenetre public enum Type{ RECTANGLE, HANN, HAMMING, TRIANGLE, BLACKMAN } public WindowFunction(Type windowType, int width, Buffer temporalSignal){ this.width = width; this.windowType = windowType; this.temporalSignal = temporalSignal; this.coef = new ArrayList(width); this.divideFactor = 1; calcCoef(); } /** Calcule l'ensemble des coefficients (masque à multiplier au signal) pour la largeur qui a été donnée * quand la fenetre a été construite */ public void calcCoef() { final float coeffHamming = 0.53836f; final float coeffBlackman2 = 0.076849f; final float coeffBlackman0 = 0.42659f; final float coeffBlackman1 = 0.49656f; switch (windowType){ case RECTANGLE: for (int i = 0; i < width; i++) { coef.add(rectangle(width, i)); } break; case HANN: for (int i = 0; i < width; i++) { coef.add(hann(width, i)); } break; case HAMMING: for (int i = 0; i < width; i++) { coef.add(hamming(width, i, coeffHamming)); } break; case TRIANGLE: for (int i = 0; i < width; i++) { coef.add(triangle(width, i)); } break; case BLACKMAN: for (int i = 0; i < width; i++) { coef.add(blackman(width, i, coeffBlackman0, coeffBlackman1,coeffBlackman2)); } break; } } /** Pondère la valeur du buffer avec celle de la fenetre */ public float getValue(int actualID){ Float valueBefore = temporalSignal.get(actualID); int id = actualID-startID; if(valueBefore == null || id < 0 || id >= width/divideFactor ) return 0; return coef.get(id*divideFactor)*valueBefore; } /** Renvoie la valeur associée à la fenêtre rectangle au point actualID donné en paramètre */ private static float rectangle(int width, int actualID) { if (actualID >= 0 && actualID <= width) { return 1f; } else { return 0f; } } /** Renvoie la valeur associée à la fenêtre Hann au point actualID donné en paramètre */ private static float hann(int width, int actualID){ if (actualID >= 0 && actualID <= width) { return (0.5f*( 1 - (float)Math.cos( (2*Math.PI*(actualID)) / (width-1)) )); } else { return 0f; } } /** Renvoie la valeur associée à la fenêtre Hamming au point actualID donné en paramètre */ private static float hamming(int width, int actualID, float coeff){ if (actualID >= 0 && actualID <= width) { return (coeff - ((1f - coeff) * (float)Math.cos(2*Math.PI*(actualID) / (width-1)))); } else { return 0f; } } /** Renvoie la valeur associée à la fenêtre triangle au point actualID donné en paramètre */ private static float triangle(int width, int actualID){ if (actualID >= 0 && actualID <= width) { return ( 1f - Math.abs(2 * (float) (actualID) / width) ); } else { return 0f; } } /** Renvoie la valeur associée à la fenêtre Blackman au point actualID donné en paramètre */ private static float blackman(int width, int actualID, float c0, float c1, float c2){ if (actualID >= 0 && actualID <= width) { return (float)( c0 - c1*Math.cos(2*Math.PI*actualID / width) + c2*Math.cos(4* Math.PI*actualID / width)); } else { return 0f; } } public void setStartID(int index){ this.startID = index; } /** * Permet la gestion d'un nombre de point sur lequel on calcule la FFT variable en fonction de la fréquence * @param divideFactor le facteur de division par lequel on divise le nombre de points maximums (puissance de 2) */ public void setDivideFactor(int divideFactor) { this.divideFactor = divideFactor; } }