Var not iterating problem • Use all row values to iterate CSV column with for loop to playNote()

Hello there,

I wanted to share my code with you, I feel that there is something crucial that I have not understood keeping me from moving forward, so I ask for your help hoping that somebody shares with me their opinion and points me in the right direction. I am writing a simple synth using the Minim library, I am getting the values from a CSV that looks like this, it has only one column:

"TIMESERIES CU_SDDR_00_BHZ, 144001 samples, 40.00 sps, 2019-07-01T21:51:52.000000, SLIST, INTEGER, Counts"
1681
1613
1608
1663

Since the CSV is heavy, 144,001 lines, I am putting the function loadTable in a separate thread. When I do println(freqValuesLoaded) at the end of the loop in the void loadData()I can see the values of each row that I need iterating inside the console. But when I call the function in draw, and then right after calling the fund I try to println(freqValuesLoaded) here, the value stays in the last row of the column. My goal is to use the dynamic, changing value of the global variable freqValuesLoaded to put it into the playNote() like this playNote(freqValuesLoaded); so that I can hear the notes changing with the frequency values from the CSV.

What I understood was that if a variable is global (variable scope) I could call the function in Draw, and right after use one of that function’s variables (updated) and since it is after I call the function, the value of the variable that I need would be updated and change in time, but I don’t understand what I am doing wrong.
Another alternative I tried was to make the function a return type, so that it would hand me the value of freqValuesLoaded, but I was not able to get it to work.

Here is my code:

import ddf.minim.Minim;
import ddf.minim.AudioOutput;

Table seisCsv;
AudioOutput out;
float freqValuesLoaded;
TableRow row;

void setup() {
  size(640, 480);
  thread("loadData");
  Minim minim = new Minim(this);
  out = minim.getLineOut();
}
void draw() {
  loadData();
  out.playNote(freqValuesLoaded);  // Variable from the loadData() that I need 
  println(freqValuesLoaded);            // to access to hear notes in realtime.

void loadData() {
  seisCsv = loadTable("CU.SDDR.1_HOUR_BHZ.ascii_SLIST.csv", "header");
 freqValuesLoaded = 0;
  for(int i = 0; i < seisCsv.getRowCount(); i++) {
     TableRow row = seisCsv.getRow(i);
     freqValuesLoaded = row.getFloat(0);
   }
}

Thank you for taking the time of reviewing this.

1 Like

1st

in what you posted, your function loadData(); has moved into draw() - not good.

2nd

don’t call loadData from draw() (1st line)

3rd

draw in itself runs 60 times per second, but you want to hear the note longer than 1/60 of a second

hence make draw like this:

  if (millis()-timer > 1000) {
    timer = millis();
     i++;
     load=true; 
  }

 if(load) {
    TableRow row = seisCsv.getRow(i);
    freqValuesLoaded = row.getFloat(0);
    out.playNote(freqValuesLoaded);  // Variable from the loadData() that I need 
    println(freqValuesLoaded);            // to access to hear notes in realtime.
    load = false; 
}

with this before setup()

int timer; 
int i;
boolean load=true;
3 Likes

Hello Chrisir, thank you so much for your help. I have found your answers / help in many other google searches concerning questions I run into while coding :slight_smile:

I want to make sure I fully understand your solution, as I am in a learning process right now with Dan Shiffman’s “Learning Processing”. You implemented a timer so that you can keep track of time and control more precisely the speed of iteration at which the values are being feed from the CSV into the sketch? If the timer is true, then parse data from CSV into variables, and then use the changing value of that variable inside playNote(), am I understanding correctly? I have to leave the for loop as well inside the void loadData() ?

I modified the code as you suggested, removed the void loadData() from draw and only left it in its thread in setup, as I understand I want it to load the CSV file, independent of setup and draw, but the console printed the Runtime Error NullPointerException and the prog stops. The line that is highlighted in red is: TableRow row = seisCsv.getRow(i); inside void draw() I tried commenting out the lines of the the for loop that you directed me to put inside void draw(), but it gave me the same error. Here is my attempt at putting the code together. As you can see I am working with CSV data, but my final goal is to parse the data and sonify in realtime, through a realtime server Iris offers. As Dan’s book teaches, I am doing everything in small parts, so as to learn my way through the whole program.

import ddf.minim.Minim;
import ddf.minim.AudioOutput;

Table seisCsv;
AudioOutput out;
float freqValuesLoaded;
TableRow row;
int timer; 
int i;
boolean load=true;

void setup() {
  size(640, 480);
  thread("loadData");
  Minim minim = new Minim(this);
  out = minim.getLineOut();
}
void draw() {

  if (millis()-timer > 1000) {
    timer = millis();
    i++;
    load=true;
  }

  if (load) {
    TableRow row = seisCsv.getRow(i);
    freqValuesLoaded = row.getFloat(0);
    out.playNote(freqValuesLoaded);  // Variable from the loadData() that I need 
    println(freqValuesLoaded);            // to access to hear notes in realtime.
    load = false;
  }
}
void loadData() {
  seisCsv = loadTable("CU.SDDR.1_HOUR_BHZ.ascii_SLIST.csv", "header");
  freqValuesLoaded = 0;
  for (int i = 0; i < seisCsv.getRowCount(); i++) {
    TableRow row = seisCsv.getRow(i);
    freqValuesLoaded = row.getFloat(0);
  }
}

I did this math: as I have 1 HOUR of seismic data, which equals to 144001 time series (values), so In order to play the equivalent of the data as a full hour in sound, I divided 144,001/3600(secs in an hour) and the result is = 40.0, so the iteration has to move 40 fps to play the notes in realtime as they were captured.
Am I doing something wrong in terms of the flow of the program?

2 Likes

You can start your draw () with

if(seisCsv==null) return;

1 Like

In fact, try without thread and call it directly

1 Like

Hola @Chrisir, and thank you for your help. I am implementing your solution, but in an OOP way since I am learning, my code was very messy and needed to organize and transition into OOP so that I can continue to develop this prog.
I believe this is an OOP question…

I am declaring and initializing an object in the main prog, and I am calling (from main) a method/function that has a timer within that object/class. The timing defined inside the function in that object has no effect in main.
I am trying to apply OOP like in the Learning Processing example,

myCar.drive();   
myCar.display();

Is this related to inheritance?
Following is only the relevant code for my problem.
In my main prog draw I have this:

void draw() {
  background(0);
  stroke(255);
  seisData.iterate();   // calling the iterate method, start iterating i
  println(seisData.i);  // When I print i from the main tab  I get faster crazy 
                        //iteration. does not adhere to the method 'iterate' timing
  float freqValuesLoaded = seisData.freqValuesLoaded;
  freqValues = freqValuesLoaded;   
  ToneInstrument myNote = new ToneInstrument(freqValues, 0.5, out); 
  out.playNote(0.5, 2.6, myNote);

and inside the class I have this:

class SeisData {

boolean load = true;
  int i = 0;
  float interval = 5000; 
  long timer;

SeisData() {
    timer = millis();
  }

void iterate() {
    if (seisCsv==null) return;
    timer = 0;    
    if (millis() - timer > interval ) {
      timer = millis();
      i++;
      println(i);  // When I print i from here I get the correct interval of iteration this correct timing . 
      load=true;
    }
  }
}

Summing it up:
When I print i from main program the timing is crazy, I get repeating values of i for the duration of my interval, and then once the interval is done, the values go at top speed. However, when I print i from within the class_method, the timing of the iteration of i is the correct one and I see it in printed the console. For this to work I need to iterate i at a specific rate in order to synthesize sound from the Table values. I really have tried to find a solution but I have been unsuccessful :frowning:

I also wanted to ask about your previous post , to really see if I understand correctly. You start if (seisCsv==null) return;
is this an exit condition? in case seisCsv is not ready?

At the end you set load=true; but at the top load is already initialized as true, why would you need to do it again?

Thank you for taking the time to read this and for your help.

Yes it starts draw all over again

Maybe the loading process is not as long as you think

Did you try it without the thread?

Unfortunately I don’t have time this week

Hello,

Yes I did, in the code posted above, it is without the thread.
When the function of object is called from main void draw, the timing specified / defined in the method of the object called has no effect. There is something I am not seeing working with classes.
No problem, I understand and thank you for your help. Hope somebody else can take a look and explain why does this happen… will keep trying.

can you post your entire code in one go, as one section please?

Hola, yes of course. The class that I have in another tab is right here below, here it goes:

import ddf.minim.*;
import ddf.minim.ugens.*;

Minim minim;
AudioOutput out;
SeisData seisData;
float freqValues;

void setup() {
  size(640, 360, P3D);
  seisData = new SeisData();
  seisData.loadData();
  minim = new Minim(this);
  out = minim.getLineOut(Minim.STEREO, 2048);  
}

void draw() {
  background(0);
  stroke(255);
  seisData.iterate();            //Calling iteration/timing method from object(contains i)
  println(seisData.i);             //When I run println(i) from here I get crazy timing/ iteration
  float freqValuesLoaded = seisData.freqValuesLoaded;
  freqValues = freqValuesLoaded;   
  ToneInstrument myNote = new ToneInstrument(freqValues, 0.5, out); 
  println(seisData.i); 
  out.playNote(0.5, 2.6, myNote); 
}

class SeisData {              // Start of class

  Table seisCsv;
  TableRow row;
  float freqValues;
  float freqValuesLoaded;
  boolean load = true;
  int i = 0;
  float interval = 5000;   // I used this long interval to verify more easily the timing function.
  long timer;

SeisData() {
  }

public void loadData() {
    seisCsv = loadTable("CU.SDDR.1_HOUR_BHZ.ascii_SLIST.csv", "header");
}

 void iterate() {
    if (seisCsv==null) return;
    timer = 0;    
    if (millis() - timer > interval ) {
      timer = millis();
      i++;                           //When I run println(i) from here I get correct timing. 
      load=true;
    }
if (load) {
      TableRow row = seisCsv.getRow(i);
      freqValuesLoaded = row.getFloat(0);
      load = false;
    }
  }
}

class ToneInstrument implements Instrument   // Start of Instrument class
{

  Oscil sineOsc;
  Oscil fm;
  AudioOutput out;

  // constructors for this instrument
  ToneInstrument( float frequency, float amplitude, AudioOutput output ) {
    // equate class variables to constructor variables as necessary 
    out = output;
    // create new instances of any UGen objects as necessary
    sineOsc = new Oscil( frequency, amplitude, Waves.SINE); //sine aqui
    fm = new Oscil(10, 0.3, Waves.TRIANGLE);  //tri aqui ( 10, 2, Waves.SINE ) ex: frequencyModulation
    fm.offset.setLastValue(40);  //have to adjust values  was 10 was 40 was 15
    fm.patch(sineOsc.frequency);
  }

  // every instrument must have a noteOn( float ) method
  void noteOn( float dur ) {
    // and patch to the output
    sineOsc.patch( out );
  }

  // every instrument must have a noteOff() method
  void noteOff() {
    // and unpatch the output 
    // this causes the entire instrument to stop calculating sampleframes
    // which is good when the instrument is no longer generating sound.
    sineOsc.unpatch( out );
    fm.unpatch( out);
  }
}

I included the main prog, plus the 2 classes that it uses. Forgot the Instrument class in first go, sry.

this does right counting

(I couldn’t run ToneInstrument)

import ddf.minim.*;
import ddf.minim.ugens.*;

Minim minim;
AudioOutput out;
SeisData seisData;
//float freqValues;

void setup() {
  size(640, 360, P3D);
  background(0);

  seisData = new SeisData();
  seisData.loadData();

  minim = new Minim(this);
  out = minim.getLineOut(Minim.STEREO, 2048);

  println("End of setup() at millis: "
    + millis() );

  seisData.timer = millis();
}

void draw() {
  background(0);

  // ----
  if (seisData.seisCsv==null) 
    return;
  // ----

  stroke(255);
  seisData.iterate();            //Calling iteration/timing method from object(contains i)

  //  println(seisData.i);             //When I run println(i) from here I get crazy timing/ iteration

  //float freqValues = seisData.freqValuesLoaded;
  //  freqValues = freqValuesLoaded;   
  // ToneInstrument myNote = new ToneInstrument(freqValues, 0.5, out); 
  //  println(seisData.i);
  text(seisData.i  
    +" :     "
    +seisData.freqValuesLoaded, 33, 33); 
  // out.playNote(0.5, 2.6, myNote);
}

// ==================================================================================

class SeisData {             
  // Start of class

  Table seisCsv;
  TableRow row;
  // float freqValues;
  float freqValuesLoaded;
  boolean load = true;
  int i = 0;
  float interval = 5000; 
  long timer=0;

  SeisData() {
    //constr
  }

  public void loadData() {
    seisCsv = loadTable("CU.SDDR.1_HOUR_BHZ.ascii_SLIST.csv", "header");
  }

  void iterate() {

    if (millis() - timer > interval ) {
      timer = millis();
      i++;                           //When I run println(i) from here I get correct timing. 
      load=true;
    }
    if (load) {
      row = seisCsv.getRow(i);
      freqValuesLoaded = row.getFloat(0);
      load = false;
    }
  }//method
  //
}//class
//
1 Like

ah, I just read this

no problem

I have actually a lot of questions regarding your code…

  • e.g. why do you have two out?

  • what is fm ?

maybe like this:


import ddf.minim.*;
import ddf.minim.ugens.*;

SeisData seisData;

void setup() {
  size(640, 360, P3D);
  background(0);

  seisData = new SeisData();
  seisData.loadData();

  println("End of setup() at millis: "
    + millis() );

  seisData.timer = millis();
}

void draw() {
  background(0);

  // ----
  if (seisData.seisCsv==null) 
    return;
  // ----

  stroke(255);
  seisData.iterate();      //Calling iteration/timing method from object(contains i)

  text(seisData.i  
    +" :     "
    +seisData.freqValuesLoaded, 33, 33);
}

// ==================================================================================

class SeisData {             
  // Start of class

  ToneInstrument myNote ; 

  Table seisCsv;
  TableRow row;
  float freqValuesLoaded;
  boolean load = true;
  int i = 0;
  float interval = 5000; 
  long timer=0;

  SeisData() {
    //constr
  }

  public void loadData() {
    seisCsv = loadTable("CU.SDDR.1_HOUR_BHZ.ascii_SLIST.csv", "header");
  }

  void iterate() {

    if (millis() - timer > interval ) {
      timer = millis();
      i++;                          
      load=true;
    }
    if (load) {
      row = seisCsv.getRow(i);
      freqValuesLoaded = row.getFloat(0);
      if (myNote!=null)
        myNote.noteOff(); 
      myNote = new ToneInstrument(seisData.freqValuesLoaded*44, 1.194); 
      myNote.noteOn( 0 ); 

      load = false;
    }
  }//method
  //
}//class
//======================================================================================

class ToneInstrument implements Instrument {
  // Start of Instrument class

  Minim minim;
  Oscil sineOsc;
  // Oscil fm;
  AudioOutput out;

  // constructor for this instrument
  ToneInstrument( float frequency, float amplitude ) {
    minim = new Minim(this);
    // equate class variables to constructor variables as necessary 
    out = minim.getLineOut(Minim.STEREO, 2048);
    // create new instances of any UGen objects as necessary
    sineOsc = new Oscil( frequency, amplitude, Waves.SINE); //sine aqui
    // fm = new Oscil(10, 0.3, Waves.TRIANGLE);  //tri aqui ( 10, 2, Waves.SINE ) ex: frequencyModulation
    // fm.offset.setLastValue(40);  //have to adjust values  was 10 was 40 was 15
    // fm.patch(sineOsc.frequency);
  }

  // every instrument must have a noteOn( float ) method
  void noteOn( float dur ) {
    // and patch to the output
    sineOsc.patch( out );
  }

  // every instrument must have a noteOff() method
  void noteOff() {
    // and unpatch the output 
    // this causes the entire instrument to stop calculating sampleframes
    // which is good when the instrument is no longer generating sound.
    sineOsc.unpatch( out );
    // fm.unpatch( out);
  }
}//class 
//
1 Like

Thank you Chrisir, it worked, but I do not know why, do not understand, what was it that made the MAIN difference for the timing of the class method to work in the main prog? could you please explain?

I saw the main 3 things is that you did in your post

:

  1. In setup you seisData.timer = millis();
  2. In draw you put the if (seisData.seisCsv==null) return;
  3. in class you initialized long timer=0;

In your latest post questions:

That is the way that instruments are constructed in minim Instrument example, you are patching them out and then stopping them.

It stands for frequency modulated, I am modulating 2 waves, a sine and a triangle.

In your most recent posting I see you included the initializing of the ToneInstrument inside the void iterate method inside of the class Seisdata could I ask why? as I am trying to keep things separate, data, instrument, playing that data, etc… That is why I was playing the note from the main prog, while having the iteration of the data within the object… I am just trying to understand…

You had this at the start of iterate.

I think this was a big mistake.

Destroying the timer

Remark

You had one object „out“ with global scope (before setup ()) and one inside the class.

I tried to unify this.

Also I put more audio stuff into iterate because we only have to start playNote once and not 60 times per second

But there are other ways of doing it

1 Like

Wow, I am understanding now, I think… I thought that I was initializing it with a value of 0 to start, since 2 lines right after you have this timer = millis();

I thought that what made the difference was this line you added in MAIN prog inside setup:

What does this mean exactly? that same line is inside the method, what is gained from putting it also inside void setup in the main prog?
saying: that timer variable will be used here… equating both timers? hope I am being clear…

This from you Chrisir, I am trying to wrap my head around… to recap, trying to explain it to myself out loud:

Draw runs 60 frames por second. I am defining a new time within a function and I am calling that function within draw. If I have playNote right after in draw, it will try to run 60 times per second, even thought the NOTE that it should play is coming from void iterate, which runs, is coming at a different rate(in this ex) interval = 5000; playNote in draw will try to play the same note, 60 times per second even thought the value will not change and stays the same for 5 secs; only changes every 5 seconds. So the way I was doing it would be a waste of computing resources Is this understanding correct? Thank you Chrisir.

I thought it’s a good idea to have it at the end of setup() so it’s right before draw() starts, and the first tone is really played 5 secs.

It would be useful when you loaded some images etc. in setup() after loading the csv.

But you are right, it’s not necessary.

That’s correct.

If minim is able to play different tones parallel it would end up to play ~ 60 * 1000 notes parallel, I don’t know

1 Like

Ahhh I understand, like a queue in music, so that everybody (inside void draw) starts playing at exactly the same time…

Chrisir and after having looked at the errors I have made, what aspects of Processing would you recommend that I revisit and study again to improve?
Here is the Table of Contents