// Gerard Paresys
// 28 06 2012
// Le dossier data doit comporter:
// lesmaries_mme.wav
// lesmaries_mme_Pitch_listing.txt
// lesmaries_mme_Intensity_listing.txt
// lesmaries_mme.TextGrid.xml (format Praat TextGrid)
// Helvetica-50.vlw
// Touche S Sauve l'ecran (format png)
// Annuler Commentaire sur les 3 lignes qui commencent par: // NomFichier
// pour ouvrir n'importe quel fichier
// Exige la library toxiclibs de Karsten Schmidt:
// http://hg.postspectacular.com/toxiclibs/downloads/toxiclibs-complete-0020.zip
/**
* Touche Espace Pause
* Touche Fleche <- Zoom Out
* Touche Fleche -> Zoom In
* Touche P Phonème
* Touche Y Syllabe
* Touche M Mot
* Clic souris dans la fenêtre d'abord
* Ouvre et joue le fichier Audio lesmaries_mme.wav
* Ouvre le fichier texte lesmaries_mme_Pitch_listing.txt généré par Praat
* Ouvre le fichier texte lesmaries_mme_Intensity_listing.txt généré par Praat
* Dessine les courbes Pitch et Intensity synchronisées avec l'Audio
* La courbe Pitch n'est pas dessinée quand pitch est "undefined"
* Chronomètre...
*
*/
// * Taper: P Phonème - Y Syllabe - M Mot - H Phonétique - O Orthographique
// * Affiche au choix 5 segmentations différentes du texte faites par Olivier Baude:
import ddf.minim.*; // pour AudioPlayer
// import toxi.math.conversion.*;
import toxi.geom.*; // pour VerletPhysics2D vp
// import toxi.math.*;
// import toxi.geom.mesh2d.*;
// import toxi.util.datatypes.*;
// import toxi.util.events.*;
// import toxi.geom.mesh.subdiv.*;
// import toxi.geom.mesh.*;
// import toxi.math.waves.*;
// import toxi.util.*;
// import toxi.math.noise.*;
// import toxi.physics2d.constraints.*;
import toxi.physics2d.behaviors.*; // pour GravityBehavior
import toxi.physics2d.*; // pour VerletPhysics2D vp;
// import processing.opengl.*;
PFont maFonte;
String NomFichierAudio = "lesmaries_mme.mp3";
String NomFichierPitch = "lesmaries_mme_Pitch_listing.txt";
String NomFichierIntensity = "lesmaries_mme_Intensity_listing.txt";
String NomFichierXML = "lesmaries_mme.TextGrid.xml";
float FacteurX = 32;
int Couche = 2; // Mot
int CoucheHaut = 0; // Mot
int CoucheBas = 1; // Mot
int PitchMini = 75 ; // 75 Hz
int PitchMaxi = 500; // 500 Hz
int QuantiteParticule = 10; // Augmenter pour diminuer Quantite
int EpaisseurCourbe = 8; // Pitch & Intensity
int Trainee = 50; // Augmenter pour diminuer Trainee
float PitchActuel = PitchMini;
boolean Alea = true;
String[] LignesPitch;
String[] LignesIntensity;
int IndexPitch = 0;
int IndexIntensity = 0;
float xAvantPitch, xApresPitch, yAvantPitch, yApresPitch;
float xAvantIntensity, xApresIntensity, yAvantIntensity, yApresIntensity;
int LigneText, x;
AudioPlayer player;
Minim minim;
float temps, DureeFichier;
boolean Probleme = false, Fin = false;
boolean ToucheEspace = false, Pause = false, Trace = false;
float[] LignePitch, LigneIntensity;
float TempsPause, TempsDebutPause = 0;
XMLElement xml1, kid1, kid2;
XMLElement[] kid1Data, kidkid1Data;
int NombreDeChild1, NombreDeChild2;
int IndexXML = 0, IndexXMLCouche4 = 0, IndexXMLHaut = 0, IndexXMLBas = 0;
float xmin, xmax;
String s1, s2, Content1, Content2;
VerletPhysics2D vp;
Vec2D center;
float angle, angleIncr;
PFont myFont;
// String letters = "go~dR go~dR@vij l@ pei d@ me gRa~ paRa~ go~dR@vij la fRa~s";
String Chaine ="AA";
// int counter = 0;
// int TailleString;
boolean NouvelleParticule = false;
void setup() {
// size(800, 600, OPENGL); // "The size() function must be the first line in setup()"
size(800, 600); // "The size() function must be the first line in setup()"
// maFonte = loadFont("Helvetica-50.vlw");
maFonte = loadFont("Verdana-48.vlw");
myFont = createFont("Impact", 48);
textFont(myFont);
angleIncr=0;
center = new Vec2D(width/2, height/2);
vp = new VerletPhysics2D();
vp.addBehavior(new GravityBehavior(new Vec2D(0, 0.001)));
// TailleString = letters.length();
// println(TailleString);
// smooth();
background(127);
stroke(160);
textAlign(LEFT, TOP);
textFont(maFonte, 16);
fill(0, 0, 0); // Texte noir
// NomFichierPitch = selectInput("select a Pitch File");
if (loadStrings(NomFichierPitch) == null) {
println("Le fichier " + NomFichierPitch + " n'existe pas");
Probleme = true;
}
else {
LignesPitch = loadStrings(NomFichierPitch);
println("Ouverture de: " + NomFichierPitch +" " + LignesPitch.length + " lignes" );
text(NomFichierPitch, 10, 5);
}
// NomFichierIntensity = selectInput("select an Intensity File");
if (loadStrings(NomFichierIntensity) == null) {
println("Le fichier " + NomFichierIntensity + " n'existe pas");
Probleme = true;
}
else {
LignesIntensity = loadStrings(NomFichierIntensity);
println("Ouverture de: " + NomFichierIntensity +" " + LignesIntensity.length + " lignes" );
text(NomFichierIntensity, 10, 25);
}
// NomFichierAudio = selectInput("select an Audio File (wav, aiff, mp3...");
if (loadStrings(NomFichierAudio) == null) {
println("Le fichier " + NomFichierAudio + " n'existe pas");
Probleme = true;
}
else {
println("Ouverture de: " + NomFichierAudio);
text(NomFichierAudio, 10, 45);
minim = new Minim(this);
player = minim.loadFile(NomFichierAudio, 2048);
}
// NomFichierXML = selectInput("select an XML File (format Praat textGrid)");
if (loadStrings(NomFichierXML) == null) {
println("Le fichier " + NomFichierXML + " n'existe pas");
Probleme = true;
}
else {
xml1 = new XMLElement(this, NomFichierXML);
NombreDeChild1 = xml1.getChildCount();
kid1Data = xml1.getChildren();
s1 = kid1Data[0].getName();
// println(s1 + " : " + NombreDeChild1 + " child(s)");
kidkid1Data = kid1Data[0].getChildren();
s2 = kidkid1Data[1].getName();
println("Ouverture de: " + NomFichierXML);
text(NomFichierXML, 10, 65);
// AfficheCouche(Couche);
}
if (! Probleme) {
player.play();
LignePitch = float(split(LignesPitch[LignesPitch.length - 1 ], " "));
DureeFichier = LignePitch[0];
println("Duree " + NomFichierPitch + " = " + DureeFichier + " sec");
LigneIntensity = float(split(LignesIntensity[LignesIntensity.length - 1 ], " "));
DureeFichier = LigneIntensity[0];
println("Duree " + NomFichierIntensity + " = " + DureeFichier + " sec");
EffaceEcran();
TempsPause = millis();
}
else exit();
frameRate(30);
}
void draw() {
temps = millis() - TempsPause;
if ((! Pause) && (! Fin)) AfficheTemps(temps);
temps = temps / 1000;
// La courbe Pitch jaune
if (IndexPitch < LignesPitch.length) {
LignePitch = float(split(LignesPitch[IndexPitch], " "));
if (Float.isNaN(LignePitch[0])) {
IndexPitch = IndexPitch + 1;
}
if (IndexPitch < 0) { //Astuce IndexPitch est > 0
LigneText = (IndexPitch * 14) + 20;
fill(0, 0, 255);
text(LignePitch[0], 50, LigneText);
fill(255, 0, 0);
text(LignePitch[1], 100, LigneText);
}
// println("temps = " + temps + " LignePitch[0] = " + LignePitch[0]);
if ((temps > LignePitch[0]) && ! Pause) {
xApresPitch = FacteurX * (width) * LignePitch[0] / DureeFichier;
if (((xAvantPitch % width) > (xApresPitch % width)) && (IndexPitch < LignesPitch.length - 10) ) EffaceEcran();
if (Float.isNaN(LignePitch[1])) {
PitchActuel = PitchMini;
IndexPitch = IndexPitch + 1;
Trace = false;
xAvantPitch = xApresPitch;
// println("NaN IndexPitch = " + IndexPitch);
}
else {
PitchActuel = LignePitch[1];
yApresPitch = YPitch(PitchActuel) ;
if (Trace) {
// stroke(255); // Ligne blanche
stroke(255, 255, 0); // Ligne jaune
strokeWeight(EpaisseurCourbe);
line(xAvantPitch % width, yAvantPitch, xApresPitch % width, yApresPitch);
}
xAvantPitch = xApresPitch;
yAvantPitch = yApresPitch;
Trace = true;
IndexPitch = IndexPitch + 1;
}
}
}
else Fin = true;
// La courbe Intensity rouge
if (IndexIntensity < LignesIntensity.length) {
LigneIntensity = float(split(LignesIntensity[IndexIntensity], " "));
if (Float.isNaN(LigneIntensity[0])) {
IndexIntensity = IndexIntensity + 1;
}
if (IndexIntensity < 0) { //Astuce IndexIntensity est > 0
LigneText = (IndexIntensity * 14) + 20;
fill(0, 0, 255);
text(LigneIntensity[0], 50, LigneText);
fill(255, 0, 0);
text(LigneIntensity[1], 100, LigneText);
}
// println("temps = " + temps + " LigneIntensity[0] = " + LigneIntensity[0]);
if ((temps > LigneIntensity[0]) && ! Pause) {
xApresIntensity = FacteurX * (width) * LigneIntensity[0] / DureeFichier;
if (((xAvantIntensity % width) > (xApresIntensity % width)) && (IndexIntensity < LignesIntensity.length - 10)) {
EffaceEcran();
}
if (Float.isNaN(LigneIntensity[1])) {
IndexIntensity = IndexIntensity + 1;
// Trace = false;
xAvantIntensity = xApresIntensity;
// println("NaN IndexIntensity = " + IndexIntensity);
}
else {
yApresIntensity = YIntensity(LigneIntensity[1]) ;
//if (Trace) {
stroke(255, 100, 100); // Ligne rouge
strokeWeight(EpaisseurCourbe);
line(xAvantIntensity % width, yAvantIntensity, xApresIntensity % width, yApresIntensity);
//}
xAvantIntensity = xApresIntensity;
yAvantIntensity = yApresIntensity;
Trace = true;
//IndexIntensity = IndexIntensity + 1;
IndexIntensity = IndexIntensity + 5;
}
}
}
else Fin = true;
// Texte courbe pitch en haut
NombreDeChild2 = kidkid1Data[CoucheHaut].getChildCount();
if (IndexXMLHaut < NombreDeChild2) {
kid1 = kidkid1Data[CoucheHaut].getChild(IndexXMLHaut);
// n = kid1.getInt("n");
xmin = kid1.getFloat("xmin");
xmax = kid1.getFloat("xmax");
Content1 = kid1.getContent();
// println("Child(" + IndexXMLHaut + "): n = " + n + " xmin = " + xmin + " xmax = " + xmax + " " + Content1);
if (Content1 == null) IndexXMLHaut = IndexXMLHaut + 1;
else if (Content1.equals("_") == true) IndexXMLHaut = IndexXMLHaut + 1;//Elimination des caracteres _ qui separe les segments
else {
// if ((temps > xmin) && ! Pause) {
// if ((temps > xmax) && ! Pause) {
if ((temps > (xmin + xmax) / 2) && ! Pause) {
fill(0, 0, 0); // Texte noir
fill(255); // Texte blanc
// textFont(maFonte, LignePitch[1] / 10);
textFont(maFonte, PitchActuel / 5); // Plantage avec Font autre que Helvetica si Size = NaN
// yApresPitch = YPitch(LignePitch[1]) ;
// text(Content1, xApresPitch % width, yApresPitch - 20);
text(Content1, xApresPitch % width, YPitch(PitchActuel) - 20);
NouvelleParticule = true;
IndexXMLHaut = IndexXMLHaut + 1;
}
}
}
// Texte courbe Intensity en bas
NombreDeChild2 = kidkid1Data[CoucheBas].getChildCount();
if (IndexXMLBas < NombreDeChild2) {
kid1 = kidkid1Data[CoucheBas].getChild(IndexXMLBas);
// n = kid1.getInt("n");
xmin = kid1.getFloat("xmin");
xmax = kid1.getFloat("xmax");
Content1 = kid1.getContent();
// println("Child(" + IndexXMLBas + "): n = " + n + " xmin = " + xmin + " xmax = " + xmax + " " + Content1);
if (Content1 == null) IndexXMLBas = IndexXMLBas + 1;
else if (Content1.equals("_") == true) IndexXMLBas = IndexXMLBas + 1;//Elimination des caracteres _ qui separe les segments
else {
// if ((temps > xmin) && ! Pause) {
// if ((temps > xmax) && ! Pause) {
if ((temps > (xmin + xmax) / 2) && ! Pause) {
fill(255, 0, 0); // Texte rouge
// textFont(maFonte, (LigneIntensity[1] - 20) / 2);
textFont(maFonte, (LigneIntensity[1] - 40) / 1);
//yApresIntensity = YIntensity(LigneIntensity[1]) ;
//text(Content1, xApresIntensity % width, yApresIntensity - 20);
text(Content1, xApresIntensity % width, YIntensity(LigneIntensity[1]) - 20);
NouvelleParticule = true;
// letters = Content1;
// Chaine = Content1;
// vp.addParticle(new Particle(0, 0)); //envoi d'une "Particle"
// println("Content1 = " + Content1);
// println("Child(" + IndexXMLBas + "): n=" + n + " xmin=" + xmin + " xmax = " + xmax + " " + Content1 + " temps = " + temps);
IndexXMLBas = IndexXMLBas + 1;
}
}
}
// Texte Particle
NombreDeChild2 = kidkid1Data[Couche].getChildCount();
if (IndexXML < NombreDeChild2) {
kid1 = kidkid1Data[Couche].getChild(IndexXML);
// n = kid1.getInt("n");
xmin = kid1.getFloat("xmin");
xmax = kid1.getFloat("xmax");
Content1 = kid1.getContent();
// println("Child(" + IndexXML + "): n = " + n + " xmin = " + xmin + " xmax = " + xmax + " " + Content1);
if (Content1 == null) IndexXML = IndexXML + 1;
else if (Content1.equals("_") == true) IndexXML = IndexXML + 1;//Elimination des caracteres _ qui separe les segments
else {
// if ((temps > xmin) && ! Pause) {
// if ((temps > xmax) && ! Pause) {
if ((temps > (xmin + xmax) / 2) && ! Pause) {
NouvelleParticule = true;
IndexXML = IndexXML + 1;
}
}
}
// Le texte "Orthographique" en blanc en bas
NombreDeChild2 = kidkid1Data[4].getChildCount(); // 4 = Couche orthographique
if (IndexXMLCouche4 < NombreDeChild2) {
// if (false) {
kid2 = kidkid1Data[4].getChild(IndexXMLCouche4); // 4 = Couche orthographique
// n = kid2.getInt("n");
xmin = kid2.getFloat("xmin");
xmax = kid2.getFloat("xmax");
Content2 = kid2.getContent();
// println("Child(" + IndexXML + "): n = " + n + " xmin = " + xmin + " xmax = " + xmax + " " + Content1);
if (Content2 == null) IndexXMLCouche4 = IndexXMLCouche4 + 1;
else if (Content2.equals("_") == true) IndexXMLCouche4 = IndexXMLCouche4 + 1;//Elimination des caracteres _ qui separe les segments
else {
if ((temps > xmin) && ! Pause) {
// if ((temps > xmax) && ! Pause) {
// if ((temps > (xmin + xmax) / 2) && ! Pause) {
noStroke(); // pas de contour
fill(0); // Rect noir
rect(0, YIntensity(40) + 20, width, 90);
fill(255); // Texte blanc
textFont(maFonte, 20);
text(Content2, 10, YIntensity(40) + 21, width-20, 60 );
// println("Child(" + IndexXMLCouche4 + "): n=" + n + " xmin=" + xmin + " xmax = " + xmax + " " + Content2 + " temps = " + temps);
IndexXMLCouche4 = IndexXMLCouche4 + 1;
}
}
}
if (frameCount % QuantiteParticule == 0) {
if (NouvelleParticule = true) {
Chaine = Content1;
vp.addParticle(new Particle(0, 0)); //envoi d'une "Particle"
NouvelleParticule = false;
}
}
fill(0, Trainee);
noStroke();
// rect(0, 0, width, height-200);
rect(0, 0, width, YIntensity(40) + 20);
pushMatrix();
translate(center.x, center.y);
rotate(radians(angle));
angle = (angle+angleIncr)%360;
// if (frameCount % 2 == 0)
// -------------------------
int nbParticles = vp.particles.size();
// println(nbParticles);
for (int i = nbParticles-1; i >=0;--i)
// for (int i = 0; i >0; --i)
// if (nbParticles > 0)
{
// int i = 0;
Particle particle = (Particle) vp.particles.get(i);
if (particle.dead()) {
vp.removeParticle(particle);
}
else {
particle.display();
}
}
popMatrix();
vp.update();
//println(nbParticles + " " + angleIncr + " " + frameRate);
// lights();
}
float YPitch(float w) {
// return ((PitchMaxi - w) / 2) + 100;
return ((PitchMaxi - w) / 2) ;
}
float YIntensity(float w) {
if (w < 40) w= 40;
// return ((100 - w) * 3) + 312;
return ((100 - w) * 3) + 420;
}
void AfficheTemps(float T) {
T = T / 1000;
noStroke();
textAlign(LEFT, BASELINE);
fill(0);
rect(width - 75, height - 13, 100, 15);
fill(255);
textFont(maFonte, 12);
text(T + " sec", width - 72, height - 2);
}
void AfficheCouche(int Couche) {
NombreDeChild2 = kidkid1Data[Couche].getChildCount();
// println(" " + s2 +" : NombreDeChild2 = " + NombreDeChild2 + " child(s)" );
// println();
// background(255);
// textFont(maFonte, 24);
textFont(maFonte, 16);
fill(255, 0, 0, 100);
for (int i = 0; i < NombreDeChild2; i++) {
XMLElement kid1 = kidkid1Data[Couche].getChild(i);
int n = kid1.getInt("n");
float xmin = kid1.getFloat("xmin");
float xmax = kid1.getFloat("xmax");
String Content1 = kid1.getContent();
// println("Child(" + i + "): n = " + n + " xmin = " + xmin + " xmax = " + xmax + " " + Content1);
if (Content1 == null) {
}
else if (Content1.equals("_") == true) //Elimination des caracteres _ qui separe les segments
{
}
else {
if (Alea) {
text(Content1, random(1, 790), random(1, 590));
}
else {
text(Content1, 5, i * 16);
}
}
}
}
void EffaceEcranAvant() {
// rbackground(255); // Fond blanc
noStroke(); // pas de contour
fill(200); // Blanc
// rect(0, YPitch(PitchMaxi), width, YIntensity(40) - YPitch(PitchMaxi));
// AfficheCouche(Couche);
textFont(maFonte, 12);
stroke(0, 0, 0); // Ligne noire
textAlign(LEFT, BASELINE);
fill(0, 0, 0); // Texte noir
line(0, YPitch(PitchMini), width, YPitch(PitchMini));
text(PitchMini + "Hz", width - 40, YPitch(PitchMini) - 16);
line(0, YPitch(PitchMaxi), width, YPitch(PitchMaxi));
text(PitchMaxi + "Hz", width - 40, YPitch(PitchMaxi) - 1);
text("Pause : Espace", width - 170, height - 2);
fill(255, 0, 0); // Texte rouge
stroke(255, 0, 0); // Ligne rouge
text("100dB", width - 40, YPitch(PitchMini) -2);
text("40dB", width - 40, YIntensity(40) - 15);
line(0, YIntensity(40), width, YIntensity(40));
// line(0, YIntensity(40), width, YIntensity(100));
xAvantPitch = 0;
yAvantPitch = YPitch(PitchMini) ;
xAvantIntensity = 0;
yAvantIntensity = YIntensity(40) ;
}
void EffaceEcran() {
// background(255); // Fond blanc
// AfficheCouche(Couche);
textFont(maFonte, 12);
textAlign(LEFT, BASELINE);
// text("A: Particle Pause: Espace", width - 270, height - 2);
text("Pause: Espace", width - 170, height - 2);
xAvantPitch = 0;
yAvantPitch = YPitch(PitchMini) ;
xAvantIntensity = 0;
yAvantIntensity = YIntensity(40) ;
}
void Debut() {
ToucheEspace = false;
Repos();
TempsPause = millis();
IndexPitch = 0;
IndexIntensity = 0;
IndexXML = 0;
IndexXMLHaut = 0;
IndexXMLBas = 0;
IndexXMLCouche4 = 0;
EffaceEcran();
PlayerAudioDebut();
}
void PlayerAudioDebut() {
player.close();
player = minim.loadFile(NomFichierAudio, 2048);
player.play();
}
void Repos() {
Pause = ToucheEspace;
if (Pause) {
player.pause();
TempsDebutPause = millis();
}
else {
player.play();
TempsPause = TempsPause + millis() - TempsDebutPause;
}
}
void keyPressed() {
// println("key = " + key);
if (key == ' ') { // barre d'espace
ToucheEspace = ! ToucheEspace;
Repos();
}
else if ( key == 'p' || key == 'P' )
{
Couche = 0; // P Phonème
Debut();
}
else if (key == 'y' || key == 'Y')
{
Couche = 1; // Y Syllabe
Debut();
}
else if (key == 'm' || key == 'M')
{
Couche = 2; // M Mot
Debut();
}
else if (key == 'h' || key == 'H')
{
Couche = 3; // H Phonétique
Debut();
}
else if (key == 'o' || key == 'O')
{
Couche = 4; // O Orthographique
Debut();
}
else if (key == 'a' || key == 'A')
{
//vp.addParticle(new Particle(0, 0)); //envoi d'une "Particle"
// particle.display();
// Alea = !Alea;
// EffaceEcran();
}
else if (key == 's' || key == 'S') saveFrame(timestamp()+"_##.png");
else if (keyPressed && (key == CODED)) { // If it's a coded key
if (keyCode == LEFT) { // Left arrow
FacteurX = FacteurX / 2;
Debut();
}
else if (keyCode == RIGHT) { // Right arrow
FacteurX = FacteurX * 2;
Debut();
}
}
// println("key = " + key + " Erreur taper Espace");
}
String timestamp() {
Calendar now = Calendar.getInstance();
println("Frame saved");
// return String.format("%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS", now);
return String.format("%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS", now);
}
void stop() {
// always close Minim audio classes when you are done with them
player.close();
minim.stop();
super.stop();
}