/* 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 processing.processes; import conteneurs.*; import generictools.Instant; import processing.buffer.Storage; import processing.buffer.TemporalBuffer; import processing.properties.FloatProperty; import processing.properties.IntProperty; import java.util.ArrayList; /** * Created by Gabriel on 21/05/2014. * Permet de passer de la détection des contours aux evenements, donc apparition et disparition de notes */ public class FreqEdgeToEvent extends IndexedProcess { IntProperty nPointRegroup; FloatProperty cutCoef; public FreqEdgeToEvent(TemporalBuffer input, int nPointRegroupMax, float cutCoef) { super("FreqEdgeToEvent", input, new TemporalBuffer(Storage.Type.ArrayList, input.getSampleRate(), Instant.fromIndex(0, input))); nPointRegroup = new IntProperty("nPoint regroupement", nPointRegroupMax); nPointRegroup.setMax(50); nPointRegroup.setMin(0); this.cutCoef = new FloatProperty("cut Coef", cutCoef); this.cutCoef.setMax(1); this.cutCoef.setMin(0); propertyManager().addProperty(nPointRegroup); propertyManager().addProperty(this.cutCoef); } @Override protected NoteEventList compute(Instant outputID) { NoteEventList listeEvent = new NoteEventList(); int id = outputID.mapToIndex(output()); Spectre r = maxRegroup(id); if(r == null) return new NoteEventList(); // Si jamais ce n'est pas un spectre de notes, on le transforme pour pouvoir travailler dessus if(!(r.getGamme() instanceof NoteGamme)){ r.castToGamme(NoteGamme.gamme()); } ArrayList ampliEdges = r.getAmplitudes(); Gamme frequencies = r.getGamme(); float currentAmpli; for (int i = 1; i < frequencies.gammeSize(); i++) { currentAmpli = ampliEdges.get(i); //Cas d'une disparation brutale de note Profil profil = new Profil(); profil.setAmplitude(Math.abs(currentAmpli), 0); if (currentAmpli < -200000f) { listeEvent.add(NoteEvent.disparitionEvent(new NoteProfiled(i, profil), -currentAmpli)); } else if (currentAmpli > 300000f) { listeEvent.add(NoteEvent.apparitionEvent(new NoteProfiled(i, profil), currentAmpli)); } } return listeEvent; } /** Supprime les maximums qui sont trop proches suivant une certaine marge de tolérance définie par cutCoeff * @param inputID l'indice du buffer d'entrée */ private Spectre maxRegroup(int inputID){ if(input().get(inputID)==null) return null; Spectre currentSpectre = ((Spectre)input().get(inputID)).copy(); if(currentSpectre==null) return null; for(int i=0; i<=nPointRegroup.getValue(); i++){ Spectre previousSpectre = input().get(inputID-i)!=null?(Spectre)input().get(inputID-i):new Spectre( ((Spectre)input().get(inputID)).getGamme()); Spectre nextSpectre = input().get(inputID+i)!=null?(Spectre)input().get(inputID+i):new Spectre( ((Spectre)input().get(inputID)).getGamme()); for (int j = 1; j < currentSpectre.getGamme().gammeSize(); j++) { float currentAmpli = currentSpectre.getAmplitude(j); float previousAmpli = (previousSpectre.getAmplitude(j)*currentAmpli)>0?Math.abs(previousSpectre.getAmplitude(j)):0; float nextAmpli = (nextSpectre.getAmplitude(j)*currentAmpli)>0?Math.abs(nextSpectre.getAmplitude(j)):-1; currentAmpli = Math.abs(currentAmpli); if(currentAmpli == 0) continue; if(previousAmpli>currentAmpli/cutCoef.getValue() || nextAmpli>currentAmpli/cutCoef.getValue()) currentSpectre.setAmplitudeAt(j, 0); } } return currentSpectre; } /** Renvoie le rapport entre 2 float */ private float rapport(float f1, float f2){ return Math.min(f1,f2)/Math.max(f1,f2); } /** * À redéfinir: Renvoie la liste des index dépendant de l'échantillon d'index inputID. * @param inputID index de l'échantillon qui est utilisé par ... * @param inputBufferID * @return La liste des indexs de sortie qui utilise inputID pour leur calcul. */ @Override protected ArrayList idUsedBy(int inputBufferID, int inputID) { if(inputID!=0) return new ArrayList(); ArrayList r = new ArrayList<>((nPointRegroup.getValue())*2+1); int outputID = Instant.fromIndex(inputID, input()).mapToIndex(output()); r.add(Instant.fromIndex(inputBufferID, input())); for(int k = 1; k < (nPointRegroup.getValue()); k++){ r.add(0, Instant.fromIndex(outputID - k,output())); r.add(Instant.fromIndex(outputID + k, output())); } return r; } /** À redéfinir: Renvoie, pour chaque buffer d'entrée la liste des index nécessaire au calcul de l'échantillon d'index outputID. * @param outputID index de l'échantillon que l'on veut calculer * @return Un tableau de même taille que getInputs(), et qui contient les liste des échantillons de chaque buffer de getInputs() nécessaire au calcul. */ @Override protected ArrayList[] idNeededFor(int outputID) { ArrayList[] t = new ArrayList[1]; ArrayList r = new ArrayList<>((nPointRegroup.getValue())*2+1); t[0] = r; if(outputID<0) return t; int inputID = Instant.fromIndex(outputID, output()).mapToIndex(input()); r.add(Instant.fromIndex(inputID, input())); for(int k = 1; k < (nPointRegroup.getValue()); k++){ r.add(0, Instant.fromIndex(inputID - k, input())); r.add(Instant.fromIndex(inputID + k, input())); } return t; } /** Renvoie le type du buffer de sortie * @return La class des échantillones du buffer de sortie */ @Override protected Class getType() { return NoteEventList.class; } @Override protected ProcessingOrder getProcessingOrder() { return ProcessingOrder.ASCENDING_ORDER; } }