how to draw a waveform for an entire sound file ?

edited February 2017 in Library Questions

Hello, I would like to draw the waveform of an entire sound file.
I have seen the example from the documentation, but this is an osciloscope, which works with a buffer, whereas I would like to draw the waveform for the entire file, like in audacity for example

import ddf.minim.*;
Minim minim; 
AudioPlayer sound; 

void setup() {
  size(300, 200);
  minim = new Minim(this);
  sound = minim.loadFile("mySound.wav");

  println(sound.length());

  for (int i=0; i < sound.length()-1024; i+=16) {
   println( sound.mix.get(i));
  }
  exit();
}

this did not work because get(i) "Gets the i sample in the buffer", wich size is 1024...
how to have all the sample value inside the file ?
==> answer is getChannel()with AudioSample (cf AudioSample )

thx.

Answers

  • ok, so we need to do FFT, event if we not draw spectra...
    this old post help https://forum.processing.org/one/topic/how-to-generate-a-simple-waveform-of-an-entire-sound-file.html

    so, not really easy. to be cotinued.

  • Answer ✓

    You can get the waveform without needing to run it through fft. The problem is processing the whole file before drawing - these things are typically run in real time and only draw the current frame's worth of data.

    You might be better off writing something, or finding something, that parsed wav files. They are generally quite simple, just raw values.

  • edited February 2017

    thx for answering.
    good idea, I forget FFT, and did it. not so far of I wanted.. audio
    (it is not the real waveform since we only have positiv value...)

      import ddf.minim.*; //
    Minim minim; 
    AudioSample sound; 
    
    void setup() {
      minim = new Minim(this);
      sound = minim.loadSample("urSound.wav", 512);
      // time is 3min 30s & nb of samples is 9 115 000
    
      size(600, 200);
      background(255);
      int bord = 10;
    
      //1. get samples values as if it was a mono files
      float[] leftSamples = sound.getChannel(AudioSample.LEFT);
      float[] rightSamples = sound.getChannel(AudioSample.RIGHT);
      float [] samplesVal = new float[rightSamples.length];
      for(int i=0 ; i <rightSamples.length ; i++){
       samplesVal[i] = leftSamples[i]+ rightSamples[i]; 
      }
    
      //2. reduce quantity : get an average from those values each  16 348 samples
      FloatList sampleAverage = new FloatList();
      int average=0;
      for (int i = 0; i< samplesVal.length; i+=1) {
        average += abs(samplesVal[i])*1000 ; // sample are low value so *1000
        if ( i % 16384 == 0 && i!=0) { 
          sampleAverage.append( average / 16384);
          average = 0;
        }
      }
    
      //3. show thoses values
      println("nb of points to display"+sampleAverage.size());
      stroke(90);
      fill(190);
      strokeWeight(0.5);
    
      for ( int i=0; i< sampleAverage.size(); i++) {
        line(i+bord, height-bord*2, i+bord, (height-bord*2) - sampleAverage.get(i));
        float time = round(  i*16384 /sound.sampleRate() );
        if (time % 30 == 0) text(round(time), i, height-bord/2);
      }
    }
    

    the question now is, how to play hat sound with a scrollbar, sync to this view :)

  • edited February 2017

    (it is not the real waveform since we only have positive value...)

    i think this is just a problem with how you are drawing them. you are using abs() in the average calculations so the positive and negative don't cancel each other out (which is correct imo), you should draw them so that half the line is above the axis, half below.

  • I have made this Capture

    it works. but... the problem is that it is not really sync :/
    maybe its because the buffer size of the AudioPlayer is not the same that the one I use for drawing the waveform (1024 versus 16384)

    import ddf.minim.*; //
    Minim minim; 
    AudioSample sound; 
    AudioPlayer soundbis;
    FloatList sampleAverage; 
    int bord; 
    
    void setup() {
      minim = new Minim(this);
      sound = minim.loadSample("urSound.wav", 2048);
      soundbis = minim.loadFile("urSound.wav");
      // time is 3min 30s & nb of samples is 9 115 000
      println(soundbis.bufferSize());
    
      size(600, 200);
      background(255);
      bord = 10;
    
      //1. get samples values as if it was a mono file
      float[] leftSamples = sound.getChannel(AudioSample.LEFT);
      float[] rightSamples = sound.getChannel(AudioSample.RIGHT);
      float [] samplesVal = new float[rightSamples.length];
      for (int i=0; i <rightSamples.length; i++) {
        samplesVal[i] = leftSamples[i]+ rightSamples[i];
      }
    
      //2. reduce quantity : get an average from those values each  16 348 samples
      sampleAverage = new FloatList();
      int average=0;
      for (int i = 0; i< samplesVal.length; i+=1) {
        average += abs(samplesVal[i])*1000 ; // sample are low value so *1000
        if ( i % 16384 == 0 && i!=0) { 
          sampleAverage.append( average / 16384);
          average = 0;
        }
      }
    
      soundbis.play();
    }
    
    void draw() {
      background(255);
      stroke(150);
      fill(190);
      strokeWeight(0.5);
      for ( int i=0; i< sampleAverage.size(); i++) {
        line(i+bord, height-bord*2, i+bord, (height-bord*2) - sampleAverage.get(i));
        float time = round(  i*16384 /sound.sampleRate() );
        if (time % 30 == 0) text(round(time), i, height-bord/2);
      }
      strokeWeight(0.7);
      stroke(20);
      float xpos = map(soundbis.position(), 0, soundbis.length(), bord, width - bord);
      line( xpos, bord, xpos, height - (bord*2));
    }
    
  • the problem is that it is not really sync

    What do you mean?

    Kf

  • @kfrajer what we ear is not what we see.
    there is an offset between the lecture of the "waveform" which I made- what we see - and the lecture of sound - what we ear.
    the lecture of the sound is in advance.

Sign In or Register to comment.