It compiles, but then it gets this runtime error
yes, another issue!!
Write an email to the people of the geomerative website
you think it’s linked to the library itself?
No, but they are good and will like it
okay, I will try! Thanks a lot…
Dear @Chrisir, I’ve fixed the map() error, wrote to Ricard Maxer who developped the Geomerative Library and to another developper, but no answer until now…
Can you post your new code without the map() error please?
Hi @Chrisir,
with pleasure but I’ve made changes since to test if with two occurences of the class Characters() it would change the result. It appears that Geomerative select the last String as a reference…
Thanks a lot for your patience and help.
L
import processing.pdf.*;
import geomerative.*;
import ddf.minim.analysis.*;
import ddf.minim.*;
String soundNameFR = "FR_01";
Minim minim;
AudioPlayer soundsFR;
FFT fftFR;
float bandHeightFR;
int x, y;
String []mess={"On me dit de te haïr et je m'y efforce",
"Je t'imagine cruel, violent, implacable",
"mais à te voir je n'ai bientôt plus de force",
"et de te blesser je suis bien incapable"};
String []message={"Tous mes camarades combattent avec rage",
"Et pleurent la nuit au souvenir des supplices",
"Infligés à leurs frères qui sont du même âge",
"et rêvent comme eux de toucher une peau lisse"};
color textColor=0;
RFont f;
float fontSize=60;
int splitGlyph = 120;
RPoint[][] pointsP;
float r = random(5, 20);
WordAttractor attractorW;
// We create 3 new lists parallel to pointsP
// List of attractors, one per glyph
WordAttractor [][] listWordAttractors;
// List of all the distances between all the attractors and the pointsP
float [][] listDistMap;
// List of vectors to replace the pointsP coordinates
PVector [][] listPV;
RShape [] gShape = new RShape[message.length];
characterSpec [] characters= new characterSpec[message.length];
RShape [] dShape = new RShape[mess.length];
characterSpec [] chars= new characterSpec[mess.length];
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
size(1920, 1920);
RG.init(this);
f = new RFont("SFNSText.ttf", int( fontSize), LEFT);
//println(message.length);
minim=new Minim(this);
soundsFR=minim.loadFile("FR_01.wav", 512);
soundsFR.play();
fftFR= new FFT(soundsFR.bufferSize(), soundsFR.sampleRate());
for (int i=0; i<mess.length; i++) {
chars[i]= new characterSpec( dShape[i], mess[i]);
println("i"+":"+i);
}
for (int i=0; i<message.length; i++) {
characters[i]= new characterSpec( gShape[i], message[i]);
//println("i"+":"+i);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void draw() {
background(0);
smooth();
soundFFTAnalyse();
translate(200, 400);
// println("i"+":"+i);
//translate(50, 50);
/*if (i%4==0) {
translate(0, -10);
}
if (i<=3) {
translate(i*20, 0);
} else if (i>3 && i<=6) {
translate(-280, 0);
translate(i*45, 0);
} else if (i==7) {
translate(-150, 0);
} else if (i>=8 && i<=10 ) {
translate(-200, 0);
translate(i*25, 0);
} else if (i>10 && i <=13) {
translate(-35, 0);
translate(i*-1, 0);
}
if (i<=8 && i%4==0) {
translate(0, 40);
} else if (i>8 && i%3==0) {
translate(50, 0);
}
if (i==11) {
translate(50, 40);
}
if (i==12 ) {
translate(-40, 0);
}*/
for (int j=0; j<mess.length; j++) {
chars[j].update();
chars[j].display();
translate(0, j+1*50);
}
for (int i=0; i<message.length; i++) {
translate(0, i+1*50);
characters[i].update();
characters[i].display();
}
translate(0, 50);
}
void soundFFTAnalyse() {
AudioPlayer fr = soundsFR;
fftFR.forward(fr.mix);
for (int i=0; i<fftFR.specSize(); i++) {
float bandDBFR = 8*log(fftFR.getBand(i)/fftFR.timeSize());
bandDBFR=constrain(bandDBFR, -1000, 1000);
bandHeightFR = map(bandDBFR*4, 0, -220, 0, height);
noStroke();
fill(255, 0, 0);
//ellipse(fr.position()/10, bandHeightFR/20, 5, 5);
}
}
class characterSpec {
String m;
int tChildCount;
RShape bShape;
RShape letterShapes;
characterSpec(RShape _letterShapes, String _m) {
letterShapes=_letterShapes;
//bShape=_bShape;
m=_m;
for (int i=0; i<m.length(); i++) {
pointsP= new RPoint [m.length()][splitGlyph];
listWordAttractors= new WordAttractor [m.length()][splitGlyph];
listDistMap = new float [m.length()][splitGlyph];
for (int n=0; n<m.length(); n++) {
for (int j=0; j<splitGlyph; j++) {
listDistMap[n][j]=100000;
}
}
listPV = new PVector[m.length()][splitGlyph];
//for (int l=0; l<m.length(); l++) {
println("m.length()"+":"+m.length());
if (m.length()>0) {
bShape= new RShape();
bShape= f.toShape(m);
RShape[]letterShapes = bShape.children;
letterShapes = bShape.children;
tChildCount = bShape.children.length;
int child=bShape.children.length;
child=max(0, bShape.children.length);
child=tChildCount;
//println("bShape.children.length"+":"+bShape.children.length);
}
}
}
void update() {
for (int k=0; k<tChildCount; k++) {
//println(tChildCount);
// println("tChildCount"+":"+tChildCount);
float posX = map(soundsFR.position(), 200, soundsFR.length(), 200, width-200);
float posY = bandHeightFR/10-350;
float d= dist(posX, 0, bShape.children[k].getCenter().x, 0);
float sx=map(d, 0, 100, 1, 1.25);
if (d<100) {
bShape.children[k].scale(sx, bShape.children[k].getCenter());
}
for (int j=0; j<splitGlyph; j++) {
float frac =(1.0/splitGlyph);
pointsP[k][j]=bShape.children[k].getPoint(j*frac);
float dist1 = dist(posX-200, posY+100, pointsP[k][j].x, pointsP[k][j].y);
if (dist1 < listDistMap[k][j]) {
// On remplace toutes les distances possibles entre la souris et les points par la distance minimale
listDistMap[k][j]=dist1;
listPV[k][j]=new PVector(posX-200, posY+100);
listWordAttractors[k][j]=new WordAttractor(listPV[k][j].x, listPV[k][j].y, pointsP[k][j]);
}
listWordAttractors[k][j].points = pointsP[k][j];
listWordAttractors[k][j].attract();
if (m==",") {
pushMatrix();
pointsP[k][j].x+=10*k;
pointsP[k][j].x-=120;
pointsP[k][j].x+=10*k;
popMatrix();
}
}
}
}
void display() {
for (int k=0; k< tChildCount; k++) {
for (int j=0; j<splitGlyph; j++) {
pushMatrix();
translate(pointsP[k][j].x, pointsP[k][j].y);
beginShape();
stroke(255);
noFill();
strokeWeight(0.5);
float angle = TWO_PI/18;
rotate(angle*j/4+noise(pointsP[k][j].x)/20);
bezier(-3*(noise(5)), 3, -6*(noise(2)), 3, -4*noise(10), -3, 3, -3);
endShape();
popMatrix();
}
}
}
}
class WordAttractor {
float force_radious =150;
float maxForce = 10;
RPoint position;
RPoint points;
float pX;
float pY;
WordAttractor(float x, float y, RPoint p) {
points =p;
position = new RPoint(x, y);
}
void attract() {
float d= points.dist(position);
if (d < force_radious) {
RPoint desired = new RPoint(points);
desired.sub(position);
desired.normalize();
desired.scale(map(d, 0, force_radious, maxForce, 0));
points.add(desired);
}
}
}
I don’t have time atm
No problem whenever you are free to test. I tried and it works with the 3 first stanzas but there is certainly a smarter and more elegant way than this one…
Thks!
Dear @Chrisir,
I’ve made some small progresses since last week: now no error with sound, and I’ve declared proper 2d arrays for the text:
for (int i=0; i<message.length; i++) {
for (int j=0; j<message[i].length; j++) {
characters[i][j]= new characterSpec( gShape[i][j], message[i][j]);
}
}
Now I’ve added a class dedicated to the sound. The sound plays fine, but when it plays, each sound file affects the whole text and not as I wish one sound deform the corresponding sentence, why?! I hope you will be able to help me with this new problem! Thanks in advance. Best, L
import processing.pdf.*;
import geomerative.*;
import ddf.minim.analysis.*;
import ddf.minim.*;
//TEXT
int indexPhraseSetFR;
int indexPhraseFR;
int x, y, i, j;
String [][]message={
{"On me dit de te haïr et je m'y efforce",
"Je t'imagine cruel, violent, implacable",
"mais à te voir je n'ai bientôt plus de force",
"et de te blesser je suis bien incapable"},
{"Tous mes camarades combattent avec rage",
"Et pleurent la nuit au souvenir des supplices",
"Infligés à leurs frères qui sont du même âge",
"et rêvent comme eux de toucher une peau lisse"},
{"Et de pouvoir enfin caresser des obus",
"Autres que ceux produits par le pouvoir obtus",
"Je rêve de quitter ces boyaux infernaux"},
{"De laisser ces furieux des deux bords du Rhin",
"Et de pouvoir embrasser ta chute de rein",
"Et porter notre amour sur les fonts baptismaux"}
};
color textColor=0;
RFont f;
float fontSize=60;
int splitGlyph = 120;
RPoint[][] pointsP;
float r = random(5, 20);
WordAttractor attractorW;
// We create 3 new lists parallel to pointsP
// List of attractors, one per glyph
WordAttractor [][] listWordAttractors;
// List of all the distances between all the attractors and the pointsP
float [][] listDistMap;
// List of vectors to replace the pointsP coordinates
PVector [][] listPV;
RShape [][] gShape = new RShape[message.length][message.length];
characterSpec [][] characters= new characterSpec[message.length][message.length];
//SOUND
SoundManager sm;
int startTime;
int loop=0;
Minim minim;
AudioPlayer background;
FFT fftFR;
float bandHeightFR;
boolean isTransitioning = false;
boolean messageOn = false;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
size(1920, 1920);
RG.init(this);
f = new RFont("SFNSText.ttf", int( fontSize), LEFT);
for (int i=0; i<message.length; i++) {
for (int j=0; j<message[i].length; j++) {
characters[i][j]= new characterSpec( gShape[i][j], message[i][j]);
}
}
//SOUND
sm= new SoundManager(this);
indexPhraseFR = 0;
indexPhraseSetFR = -1;
minim= new Minim(this);
background = minim.loadFile("WAR.wav");
// TIME
startTime=millis();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void draw() {
background(0);
smooth();
sm.update();
translate(300, 400);
for (int i=0; i<message.length; i++) {
for (int j=0; j<message[i].length; j++) {
//indexPhraseFR = j;
//indexPhraseSetFR = i;
// println("i"+":"+i);
//println("j"+":"+j);
translate(0, 50);
if (i==0 && j<=3) {
translate(j*20, 0);
}
if (i==1 && j<=2) {
translate(j*-20, 0);
} else if (i==1 && j==3) {
translate(j*-50, 0);
}
if (i==2 && j<=2) {
translate(j*20, 0);
}
if (i==3 && j<=2) {
translate(j*-20, 0);
}
characters[i][j].update();
characters[i][j].display();
}
translate(0, j+1*50);
}
messageOn=true;
}
void initAttractorFR(int i, int j) {
attractorW= new WordAttractor(x, y, pointsP[i][j]);
}
void nextPhraseSetFR() {
messageOn=true;
}
void nextPhrase() {
//println(phraseSet[indexPhraseSet][indexPhrase]);
}
class characterSpec {
String m;
int tChildCount;
RShape bShape;
RShape letterShapes;
characterSpec(RShape _letterShapes, String _m) {
letterShapes=_letterShapes;
//bShape=_bShape;
m=_m;
for (int i=0; i<m.length(); i++) {
pointsP= new RPoint [m.length()][splitGlyph];
listWordAttractors= new WordAttractor [m.length()][splitGlyph];
listDistMap = new float [m.length()][splitGlyph];
for (int n=0; n<m.length(); n++) {
for (int j=0; j<splitGlyph; j++) {
listDistMap[n][j]=100000;
}
}
listPV = new PVector[m.length()][splitGlyph];
//for (int l=0; l<m.length(); l++) {
//println("m.length()"+":"+m.length());
if (m.length()>0) {
bShape= new RShape();
bShape= f.toShape(m);
RShape[]letterShapes = bShape.children;
letterShapes = bShape.children;
tChildCount = bShape.children.length;
int child=bShape.children.length;
child=max(0, bShape.children.length);
child=tChildCount;
//println("bShape.children.length"+":"+bShape.children.length);
}
}
}
void update() {
for (int k=0; k<tChildCount; k++) {
float d= dist(attractorPosXFR, 0, bShape.children[k].getCenter().x, 0);
float sx=map(d, 0, 100, 1, 1.45);
if (d<100) {
bShape.children[k].scale(sx, bShape.children[k].getCenter());
}
for (int j=0; j<splitGlyph; j++) {
float frac =(1.0/splitGlyph);
pointsP[k][j]=bShape.children[k].getPoint(j*frac);
float dist1 = dist(attractorPosXFR -200, attractorPosYFR +100, pointsP[k][j].x, pointsP[k][j].y);
if (dist1 < listDistMap[k][j]) {
// On remplace toutes les distances possibles entre la souris et les points par la distance minimale
listDistMap[k][j]=dist1;
listPV[k][j]=new PVector(attractorPosXFR -200, attractorPosYFR +100);
listWordAttractors[k][j]=new WordAttractor(listPV[k][j].x, listPV[k][j].y, pointsP[k][j]);
}
listWordAttractors[k][j].points = pointsP[k][j];
listWordAttractors[k][j].attract();
pushMatrix();
if (m==",") {
pointsP[k][j].x+=10*k;
}
pointsP[k][j].x-=120;
pointsP[k][j].x+=10*k;
popMatrix();
}
}
}
void display() {
for (int k=0; k< tChildCount; k++) {
for (int j=0; j<splitGlyph; j++) {
//RPoint attractorPositFR = new RPoint(attractorPosXFR, attractorPosYFR);
//float dist = pointsP[k][j].dist(attractorPositFR);
pushMatrix();
translate(pointsP[k][j].x, pointsP[k][j].y);
beginShape();
stroke(255);
noFill();
strokeWeight(0.5);
float angle = TWO_PI/18;
rotate(angle*j/4+noise(pointsP[k][j].x)/20);
bezier(-3*(noise(5)), 3, -6*(noise(2)), 3, -4*noise(10), -3, 3, -3);
endShape();
popMatrix();
if (k==indexPhraseFR) {
pushMatrix();
translate(pointsP[k][j].x, pointsP[k][j].y);
RPoint attractorPosFR = new RPoint(attractorPosXFR, attractorPosYFR);
attractorPosFR = new RPoint(attractorPosXFR, attractorPosYFR);
float d = pointsP[k][j].dist(attractorPosFR);
if (d<100) {
d = map(d, 50, 0, 1, 0);
noFill();
stroke(255, 200);
}
float angle_01 = TWO_PI*10;
//rotate (j/angle*frameCount/10);
rotate (j/angle_01*2);
bezier(-2*(noise(10)), 10, 10*(noise(10)), -5, 2*noise(5), -10, 10, attractorPosFR.x/20);//
popMatrix();
}
}
}
}
}
import ddf.minim.analysis.*;
import ddf.minim.*;
// variable 'public'
String []soundNamesFR = {"FR_01", "FR_02", "FR_03", "FR_04", "FR_05", "FR_06", "FR_07", "FR_08", "FR_09", "FR_10", "FR_11", "FR_12", "FR_13", "FR_14"};
float attractorPosXFR, attractorPosYFR;
class SoundManager {
//SOUND
Minim minim;
AudioPlayer[]soundsFR;
FFT fftFR;
float transitionTime = 0;
int startTransitionTime;
int transitionDuration = 1500;
SoundManager(PApplet app) {
minim = new Minim(app);
soundsFR = new AudioPlayer[soundNamesFR.length];
for (int i =0; i<soundNamesFR.length; i++) {
soundsFR[i] = minim.loadFile(soundNamesFR[i]+".wav", 512);
}
}
void update() {
if (isTransitioning) {
if (millis() >= startTransitionTime+transitionDuration) {
// transition end
// si c'est pas fini on passe au suivant
if (indexPhraseSetFR < soundsFR.length) {
isTransitioning=false;
transitionTime=0;
nextPhraseSetFR();
playSound();
// si on a lu tous les groupes on recommence à zero
} else if (indexPhraseSetFR == soundsFR.length && millis() >= startTransitionTime+transitionDuration) {
// reset from the beginning
isTransitioning=false;
transitionTime=0;
indexPhraseSetFR=0;
indexPhraseFR=0;
nextPhraseSetFR();
background.shiftGain(-20, -80, 1000);
background.rewind();
background.pause();
startTime = millis();
playSound();
background.play();
background.shiftGain(-80, -20, 1000);
}
} else if (millis() <= startTransitionTime+transitionDuration) {
// we are transiting
transitionTime = map(millis(), startTransitionTime, startTransitionTime+transitionDuration, 0., 1.);
}
} else {
if ( indexPhraseSetFR==-1) {
// Initialise all
indexPhraseSetFR=0;
indexPhraseFR=0;
playSound();
nextPhraseSetFR();
background.play();
background.shiftGain(-80, -20, 1000);
} else if ( !soundsFR[indexPhraseFR].isPlaying()) {
// sound file is finished read next one
indexPhraseFR++;
//println("soundsFR.length"+":"+ soundsFR.length);
println("indexPhraseFR"+":"+ indexPhraseFR);
println("indexPhraseSetFR"+":"+indexPhraseSetFR);
if ( isTransitioning==false && indexPhraseFR >= soundsFR.length) {
// If phrases'index is greater than the stanza's index then go on to the next stanza
indexPhraseFR=0;// 1rst sentence
indexPhraseSetFR++;// increase stanza's index
isTransitioning = true;
startTransitionTime = millis();
} else {
//go to the next phrase
nextPhrase();
}
if (millis() >= startTransitionTime+transitionDuration) {
playSound();
}
} else {
// we're reading the sound file
// analyse of the sound
soundFFTAnalyse();
wordAttractorToSound();
}
}
}
void pauseSound() {
AudioPlayer fr = soundsFR[indexPhraseFR];
fr.rewind();
fr.pause();
fftFR = new FFT(fr.bufferSize(), fr.sampleRate());
}
void playSound() {
AudioPlayer fr = soundsFR[indexPhraseFR];
fr.rewind();
fr.play();
fftFR = new FFT(fr.bufferSize(), fr.sampleRate());
attractorPosXFR = 0;
attractorPosYFR =0;
bandHeightFR = 0;
}
void soundFFTAnalyse() {
AudioPlayer fr = soundsFR[indexPhraseFR];
fftFR.forward(fr.mix);
for (int i =0; i< fftFR.specSize(); i++) {
float bandDBFR = 10*log(fftFR.getBand(i)/fftFR.timeSize());
bandDBFR = constrain(bandDBFR, -1000, 1000);
bandHeightFR = map(bandDBFR*4, 0, -220, 0, height);
}
}
void wordAttractorToSound() {
AudioPlayer fr = soundsFR[indexPhraseFR];
initAttractorFR(indexPhraseFR,indexPhraseFR);
attractorPosXFR = map(fr.position(), 0, fr.length(), 100-width/5, width-100+width/7);
attractorPosYFR = bandHeightFR/8-350;
attractorW.moveTo(attractorPosXFR, attractorPosYFR);
attractorW.attract();
//wAttractorFR.display();
}
}
class WordAttractor {
float force_radious =150;
float maxForce = 10;
RPoint position;
RPoint points;
float pX;
float pY;
WordAttractor(float x, float y, RPoint p) {
points =p;
position = new RPoint(x, y);
}
void attract() {
float d= points.dist(position);
if (d < force_radious) {
RPoint desired = new RPoint(points);
desired.sub(position);
desired.normalize();
desired.scale(map(d, 0, force_radious, maxForce, 0));
points.add(desired);
}
}
void moveTo(float x, float y) {
position.x=x;
position.y=y;
}
}
Hi!
I am afraid I don’t have time…
Hi!
Well if you find a bit of time in the coming days just to help me to find my way, how to debug, I’m doing my best and it’s the last touch to this project! Thanks a lot in advance.
Best,
L
you got mail…
Here it is : l.mareschal@free.fr
thanks @Chrisir
?! I misunderstood ?! I haven’t received anything yet…
just a short reply:
Remark
I like it that you work with tabs
Remark
This should be in the soundmanager class [I guess, or do you play two sounds at the same time? Then forget my remark] and not before setup() (in fact you already have it in the class but it’s duplicate before setup()):
Minim minim;
AudioPlayer background;
FFT fftFR;
also this (which is in setup() but should be in the class instead):
background = minim.loadFile(“WAR.wav”);
Your question
each sound file affects the whole text and not as I wish one sound deform the corresponding sentence, why
WordAttractor attractorW, attractorPosXFR
etc. are modified by wordAttractorToSound()
(class SoundManager
)
but the problem is imho that all sentences do use these variables attractorW, attractorPosXFR etc.
so no wonder all sentences are affected / changed
To solve this problem: umhh…
Do you want to play 1 soundfile that affects sentence 1 and then when it (1) has ended soundfile 2 starts and 2 affects sentence 2 ?
when I look at your draw() I see
translate(300, 400);
for (int i=0; i<message.length; i++) {
for (int j=0; j<message[i].length; j++) {
which means you put out all the letters at once (which is ok) and modify them all (which is not ok).
So you could have one variable storing which sentence is currently modified (1,2,3…)
if(sentenceNumberCurrentlyModified == i) {
characters[i][j].update();
}
characters[i][j].display();
now initially sentenceNumberCurrentlyModified is 0, every time when you start a new sound in update()
in class SoundManager
say sentenceNumberCurrentlyModified ++;
Chrisir
Thank you so much dear @Chrisir to take of your time to help me on sunday!
Do you want to play 1 soundfile that affects sentence 1 and then when it (1) has ended soundfile 2 starts and 2 affects sentence 2 ?
Yes exactly.
So you could have one variable storing which sentence is currently modified (1,2,3…)
ok I will try this… I will let you know if it works ;)) Thank you so much for this great pedagogical approach it helps me to understand my mistakes…
Didn’t have time to do it… sorry…