166 lines
5 KiB
Java
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;
|
|
}
|
|
}
|