Storing data into an array (processing.sound)

please format code with </> button * homework policy * asking questions

Hello

I’m trying to store data from a sound file into an array so that I can use it to draw with. I’ve come a bit further on with my problem but I have an issue that I can’t get my head around.

The array stores one ‘audio block’ at a time so when I draw, my visuals are staggered. Is there a way I can load all the data and then call on this data once the array is complete (i.e. after my if command within the draw line has ran?

I’ve posted my code below - thank you for any help in advance

Becky


import processing.sound.*;

SoundFile sample;
Amplitude rms;

// Used for storing the smoothed amplitude value
float sum;

float[] ampHistory;

int i;


void setup() {
  //noLoop();
  size(640, 360);
  background(255);

  sample = new SoundFile(this, "pigeon_01.wav");
  sample.play();

  rms = new Amplitude(this);
  rms.input(sample);
}      

void draw() {
  
  int numberSteps = 150;
  

  if (i < numberSteps) {

      i += ceil(rms.analyze());
  
      sample.frames();
  
      sum += (rms.analyze() - sum) * 0.25;

      float rms_scaled = sum * (height/2) * 5;
  
      println(rms_scaled, i);
  
  ampHistory = new float[numberSteps+1];
  ampHistory[i] = rms_scaled;
    

}

  stroke(0);
  strokeWeight(5);

beginShape();

for (int j = 1; j < numberSteps; j+= 10) {
   
    vertex(j*2, 100 - ampHistory[j]);  

}

endShape();

}

Hi Becky,

I am not sure I fully understood your question could you elaborate a bit more or share what kind of final output you are after. My brain sometimes works better backwards from the goal.

I don’t have your sample but I just loaded a song and got the following output. Is this what you are getting as well?

processingHelp

Hello

Thank you so much for responding - really appreciate your time!

The output you shared is similar but I’m getting triangles (so I must be getting two values at a time).

I basically want to create a line to show the amplitude of the entire song - with one point representing one frame (i.e. one value for each frame) . I’ve attached a bit of code that is similar to the last but I’ve replaced the last bit with circles - essentially I’m wanting to create a line that links up all those circles.

My problem seems to be how I’m using the arrays but I don’t fully understand what I should be doing. I essentially want to play the entire song and store the individual amp values per frame for the entire song into an array AND THEN do my drawing. However, this is the bit I must be doing wrong but I’m not sure if it’s my logic (and I’m not even on the right track) or the logic is ok but my code is wrong…

Do you know if it’s to do with audio samples vs audio files?

Thanks again

Becky

import processing.sound.*;

// Declare the processing sound variables 
SoundFile sample;
Amplitude rms;

float sum;

float[] ampHistory;

int i;

void setup() {
  //noLoop();
  size(640, 360);
  background(255);

  //Load and play a soundfile and loop it
  sample = new SoundFile(this, "pigeon_01.wav");
  sample.play();

  // Create and patch the rms tracker
  rms = new Amplitude(this);
  rms.input(sample);
}      

void draw() {
  
  stroke(0);
  strokeWeight(5);
  
  int numberSteps = 150;
  

  if (i < numberSteps) {
   
  i += ceil(rms.analyze());
  
  sample.frames();
  
  // smooth the rms data by smoothing factor
  sum += (rms.analyze() - sum) * 0.25;
  float rms_scaled = sum * (height/2) * 5;
  
  println(rms_scaled, i);
  
  ampHistory = new float[numberSteps+1];
  ampHistory[i] = rms_scaled;
    
circle(i*2,100 - ampHistory[i],20);

}

  stroke(0);
  strokeWeight(5);


}
1 Like

No problem, happy to help! Do you want an output similar to this:

processingHelp2

You could use a line or rectangle to draw the heights but I just wanted to make it a simple visual. In desired ‘audio blocks’ as the song is progressing an average amplitude is being calculated and then passed to your array of ampHistory. As that ampHistory grows in ‘audio blocks’ new lines segments are being drawn to the canvas?

Hello

Thanks again for you help. It’s not so much what I’m going to do at the end that I’m struggling with - it’s more the storing it within the array. Once I have the array I was just going to do a simple bezier line that will link up the array[i] with array[i - 1] etc, but I’m struggling with the array. I think it is my logic.

I’ve attached another bit of code. Essentially, I’m trying to get what I’m printing to the console (the i and the rms_scaled) into an array where each value of rms_scaled is positioned at it’s I value).

import processing.sound.*;

// Declare the processing sound variables
SoundFile sample;
Amplitude rms;


float[] ampHistory;

int i;


void setup() {
  size(640, 360);

  sample = new SoundFile(this, "pigeon1.mp3");
  sample.play();

  // Create and patch the rms tracker
  rms = new Amplitude(this);
  rms.input(sample);
}


void draw() {

  background(125, 255, 125);
  stroke(1);
  noFill();
  
  if (sample.isPlaying()) {
    
 //   for (int j = 0; j < 165; j++) {
    
  float rms_scaled = map(rms.analyze()*10,0.0,10.0,20.0,350.0);

  i += ceil(rms.analyze());
  
  //ampHistory = new float[165];
  //ampHistory[j] = rms_scaled;

  println(i,rms_scaled);

  ellipse(width/2 + i, height/2, rms_scaled, rms_scaled);
//  }
  
  
}

//println(ampHistory[5]);
}

I’ve commented out what I was trying to do with the arrays as they’re not working but you can see my thinking. What seems to be happening is that instead of having an array of length 165 (as this is the max value of my i value (i.e. how many unique amp values I’m getting), I seem to have 165 arrays of length 165 (I think). As when I query the array at position 5 for example, I have 0 in all positions except position 5. I tried to treat it as a two dimensional array and went even further down the wrong track.

I really appreciate your time so not wanting you to have to do this for me, but even a pointer as where to look as feel I’m thinking about this incorrectly… I’ve looked at array lists over arrays but it’s almost as if, even though I have my i value that counts to 165, my frame rate must be counting to 12000 odd and I think I’m getting caught up between the two…

You may try out an ArrayList of float[]:

import java.util.List;

static final int SAMPLE = 165;
final List<float[]> ampHist = new ArrayList<float[]>();

void draw() {
  final float[] amps = new float[SAMPLE];
  ampHist.add(amps);
  print(ampHist.size(), TAB);

  for (int i = 0; i < SAMPLE; ++i) {
    amps[i] = random(20, 350);
  }
}

Thank you for this - I’ll read into that and have a look at it within my code - thank you so much!

Becky

Sorry for not quite getting the output you are after but I was trying to understand if the issue was solely with your array or the way you were trying to draw the data or both. I would also suggest using an ArrayList for storing data. This is very similar to the List mentioned by @GoToLoop just initialized a bit different. You can find documentation in the Processing Reference:

If you really want to only display your curve after all of the data has been collected you can use the sample.isPlaying() method to wrap your code that displays an output. This will delay the drawing until all the sound file data has been collected.

Finally, something I find useful when collecting sound data and trying to use it throughout my code is the map function in processing. I saw you were using some scaling to adjust the amplitude values. You can also do this by mapping a value from one range to another. This is especially useful with .analyze() since you know it will return a value between 0 and 1.

I hope that is useful. Please post if the ArrayList was helpful or if you have any other questions.

Hello

Don’t apologise - it’s been really helpful and it’s really appreciated. I hope my message didn’t sound as if I was ungrateful - that wasn’t the case at all - I just didn’t think I’d been clear about my issue in the first place so just wanted to mention where I was having most issues :slight_smile:

The array list looks really helpful - I’ll take a look at this - thank you.

I did do a bit of mapping but my numbers were all pretty low so I started fiddling about with my very messy formula :slight_smile:

Thanks again

Becky

p.s. I’ll post again once I’ve looked properly at the array list

Sorry - back again. Just one more question if that’s ok so that I can try and understand what’s happening.

I have the isplaying function and the array list but at the end of the draw function (and outwit the if isplaying function), I’ve queried the size of the array. I assumed it would be 165 (as the loop would have collected all the data and I now have a static array. but the console counts up to 165 - so the array is still dynamic even outwith the function that I’m collecting the data. Is that right?

Thanks again

Becky

import processing.sound.*;
import java.util.List;

// Declare the processing sound variables
SoundFile sample;
Amplitude rms;

static final int SAMPLE = 165;
final List<float[]> ampHist = new ArrayList<float[]>();

int i;

void setup() {
  size(640, 360);

  sample = new SoundFile(this, "pigeon1.mp3");
  sample.play();

  // Create and patch the rms tracker
  rms = new Amplitude(this);
  rms.input(sample);
}


void draw() {

  background(125, 255, 125);
  stroke(1);
  noFill();
  
  if (sample.isPlaying()) {
        
  float rms_scaled = map(rms.analyze(),0.0,1.0,20.0,350.0);

  i += ceil(rms.analyze());
  
    final float[] amps = new float[SAMPLE];
    ampHist.add(amps);
    
    //print(ampHist.size(), TAB);
    
    for (int i = 0; i < SAMPLE; ++i) {
    amps[i] = rms_scaled;
  }
}
  println(ampHist.size());
}

Seems like you’re filling up the float[] array w/ the same rms_scaled value.

So you don’t need a 2D container. Just a 1D is enough:

final FloatList ampHist = new FloatList();

void draw() {
  final float rmsScaled = rms.analyze() * 330 + 20;
  ampHist.append(rmsScaled);
  print(ampHist.size(), TAB);
}

Thank you - really really appreciate your help.

Thanks again

Becky

I think the main question is how we use the function of the sound library to monitor the sound:

  • The library assumes we play the sound/song continuously and we draw something.

  • The OP wants to know whether it’s possible to read the entire song data at once without playing the song (so it’s faster). I think (this is my opinion) that’s the main question here and not all answers address this. I am not sure whether the library has such a command.

  • This would be done in setup() and then we have one array to work with in draw().

Chrisir

there might be some java bits in here that give you some inspiration, this is using Minim sound library to load a song into an array and capture frequencies, function audioToArray() does the main bit