235 lines
7.4 KiB
Java
235 lines
7.4 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 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;
|
||
}
|
||
}
|