reversound/src/processing/PostProcessScript.java
2014-06-16 16:48:34 +02:00

235 lines
7.4 KiB
Java
Raw Blame History

/*
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 processing;
import generictools.Instant;
import processing.buffer.NoteBuffer;
import javax.swing.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
/**Created by gaby on 03/06/14.
* Script qui sert à l'exportation vers Lilypond. Regroupe tous les algo de post-traitement nécéssaires à cette exportation. */
public class PostProcessScript implements Runnable{
private NoteBuffer buffer;
private float tolerance = 0.08f;
private float progress = 0;
Runnable callBack;
Thread thread = null;
private static PostProcessScript script = null;
private PostProcessScript(NoteBuffer buffer, Runnable callBack){
this.buffer = buffer;
this.callBack = callBack;
}
/**
* Lance le script
* @param buffer
* @param callBack
*/
public static void launchScript(NoteBuffer buffer, Runnable callBack){
interrupt();
PostProcessScript script = new PostProcessScript(buffer, callBack);
script.thread = new Thread(script);
script.thread.start();
script = null;
}
public static void interrupt(){
if(script!=null && script.thread!=null && script.thread.isAlive())
script.thread.interrupt();
script = null;
}
@Override
public void run() {
unifyTempo();
// System.out.println("NOTES:");
//
// for (int i = 0; i < buffer.getNotesNbr(); i++) {
// System.out.println("\t" + buffer.getNote(i).getNoteName() + " (" + buffer.getNote(i).getUnifiedDuration() + ")");
// }
JFileChooser jfc = new JFileChooser();
jfc.setDialogTitle("Choix du dossier de sortie");
jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int ret = jfc.showOpenDialog(null);
if(ret != JFileChooser.APPROVE_OPTION)
return;
File file = new File(jfc.getSelectedFile().getPath()+"/exportLilypond.txt");
System.out.println(jfc.getSelectedFile().getPath()+"/exportLilypond.txt");
try {
if(!file.exists())
file.createNewFile();
FileWriter fileWriter = new FileWriter(file);
fileWriter.write(toLilyPond());
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
return;
}
if(callBack!=null)
try {
callBack.run();
} catch (Exception e) {
e.printStackTrace();
}
}
private String toLilyPond(){
String r = "<< {";
for (int i = 0; i < buffer.getNotesNbr(); i++) {
r+=buffer.getNote(i).getEnglishNoteName() + buffer.getNote(i).getUnifiedDuration() + " ";
}
r+="} >>";
return r;
}
/** Cherche le tempo du morceau en se basant sur les écarts entre les notes.
* A partir de la, il donne a chaque note une duree (ronde, blanche noire, croche, etc) et permet de trouver le rythme */
private void unifyTempo(){
ArrayList<Float> listEcarts = calculeEcarts(bufferSortOut(buffer));
ArrayList<Float> EcartsReference = new ArrayList<>();
ArrayList<Integer> nEcartParType = new ArrayList<>();
//Cr<43>ation des cat<61>gories de r<>f<EFBFBD>rence, tri<72>es par ordre croissant
EcartsReference.add(listEcarts.get(0));
nEcartParType.add(1);
for (int i = 1; i < listEcarts.size(); i++) {
float currentEcart = listEcarts.get(i);
boolean newCategoryNeeded = true;
for (int j = 0; j < EcartsReference.size(); j++) {
//Si on est dans la marge de tolerance d<>finie en param<61>tre, on red<65>finit la r<>f<EFBFBD>rence gr<67>ce <20> une moyenne pond<6E>r<EFBFBD>e
if(currentEcart>((1-tolerance)*EcartsReference.get(j)) && currentEcart<((1+tolerance)*EcartsReference.get(j))){
EcartsReference.set(j, ( (nEcartParType.get(j)*EcartsReference.get(j))+ currentEcart) / (nEcartParType.get(j)+1) );
nEcartParType.set(j, nEcartParType.get(j)+1);
newCategoryNeeded = false;
}
}
//Sinon cr<63>ation d'une nouvelle cat<61>gorie si aucune existante ne convient
if(newCategoryNeeded){
int j = 0;
while(j<EcartsReference.size() && EcartsReference.get(j)<= currentEcart){
j++;
}
EcartsReference.add(j,currentEcart);
nEcartParType.add(j,1);
}
}
//Definition des ecarts unifies : l'ecart le plus utilise est la noire par défaut sauf si dans ce cas, le plus grand est > à une ronde
ArrayList<String> UnifiedEcarts = new ArrayList<>(EcartsReference.size());
int indexEcartMostUsed = 0;
int maxUsed = 0;
for (int i = 0; i < nEcartParType.size(); i++) {
if( nEcartParType.get(i)> maxUsed){
maxUsed = nEcartParType.get(i);
indexEcartMostUsed = i;
}
}
for (int i = 0; i < nEcartParType.size(); i++) {
UnifiedEcarts.add("0");
}
//Cas où on se retrouve avec le max plus grand qu'une ronde
while(indexEcartMostUsed < EcartsReference.size()-1 && EcartsReference.get(indexEcartMostUsed)*(4+tolerance)>EcartsReference.get(EcartsReference.size()-1)){
indexEcartMostUsed++;
}
//Donne à chaque note une durée unified
for (int i = 0; i < buffer.getNotesNbr(); i++) {
double duration = i!=buffer.getNotesNbr()-1?buffer.getNote(i+1).getStart().substract(buffer.getNote(i).getStart()):buffer.getNote(i).getDuration();
double fac = Math.log(EcartsReference.get(indexEcartMostUsed)*4/ duration)/Math.log(2);
buffer.getNote(i).setUnifiedDuration(String.valueOf(Math.round(Math.pow(2, (int) fac))) + (fac % 1 < 0.5 ? "." : ""));
}
System.out.println("ECARTS:");
for (int i = 0; i < UnifiedEcarts.size(); i++) {
System.out.println("\t" + EcartsReference.get(i) + " (" + UnifiedEcarts.get(i) + ")");
}
}
/** Trie les instants de d<>part des notes dans l'ordre croissant
* @param buffer le buffer dont les instants sont <20> trier */
private ArrayList<Instant> bufferSortOut(NoteBuffer buffer){
ArrayList<Instant> tmp = new ArrayList<>();
ArrayList<Instant> res = new ArrayList<>();
// On r<>cup<75>re tous les instans de d<>part
for (int i = 0; i < buffer.getNotesNbr(); i++) {
tmp.add(buffer.getNote(i).getStart());
}
//Tri par ordre croissant
res.add(tmp.get(0));
for (int i = 1; i < tmp.size(); i++) {
int j = 0;
while(j<res.size() && res.get(j).isLowerOrEquThan(tmp.get(i))){
j++;
}
res.add(j, tmp.get(i));
}
return res;
}
/** Calcule les <20>carts entre les instants de d<>part successifs
* @param instantList la liste des instants tri<72>s par ordre croissant */
private ArrayList<Float> calculeEcarts(ArrayList<Instant> instantList){
ArrayList<Float> res = new ArrayList<>();
for (int i = 1; i < instantList.size(); i++) {
res.add(instantList.get(i).substract(instantList.get(i - 1)));
}
return res;
}
private boolean updateProgress(float progress){
try {
Thread.sleep(0);
} catch (InterruptedException e) {
return true;
}
this.progress = progress;
return false;
}
public static float getProgress(){
if(script == null)
return -1;
return script.progress;
}
}