Who knows well Geomerative?!

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…

1 Like

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…

1 Like

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

1 Like

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…

1 Like

Didn’t have time to do it… sorry…