reversound/src/generictools/WindowFunction.java
2014-06-16 16:48:34 +02:00

166 lines
5 KiB
Java

/*
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 <http://www.gnu.org/licenses/>.
*/
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<Float> temporalSignal;
private ArrayList<Float> 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<Float> temporalSignal){
this.width = width;
this.windowType = windowType;
this.temporalSignal = temporalSignal;
this.coef = new ArrayList<Float>(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;
}
}