Minim FFT returning zero for some files

edited June 2017 in Library Questions

Hello,

I'm writing a program which takes the FFT of various files in a folder and then writes the FFT data to a text file for a machine learning algorithim. However, for many of the files I process, I get zero out for all bands causing me to lose lots of potential data.

I'm also getting the error of "JavaSound Minim Error: Error Reading from File - Stream Closed" on many of the files, though I'm not sure if it affects the FFT data.

Here's my code (I'm new to coding so I'm open to pointers on my code too):

import ddf.minim.analysis.*;
import ddf.minim.*;
import java.io.*;

Minim       minim;
AudioPlayer player;
FFT         fft;
FileWriter fw;

int counter = 0;

void setup()
{

 minim = new Minim(this);

 try 
 {

     //create .txt file to record data
     fw = new FileWriter("audioRawData.txt");
     //run data() which reads .wav files and outputs FFT data to text file
    data();


 }

 catch (IOException e) 
 {

 }

}


 void data()
{

  try 
  {

  //list files in a directory given by filePath  
  String filePath = "";  
  File[] files = new File(filePath).listFiles();

  //loop thru files
  for(File file : files) 
  {
   //get name of file
   String fileName = file.getName();

   //only process if .wav file
   if (fileName.contains(".wav"))
   {

     //counter to keep track
     counter = counter + 1 ;

     //print counter and file name to keep track of what's being processed
     println(counter);
     println(fileName);

     //load file in Minim and play using AudioPlayer
     player = minim.loadFile(filePath + fileName);
     player.play();

     //create new FFT and use Hamming window
     fft = new FFT(player.bufferSize(), player.sampleRate());
     fft.window(FFT.HAMMING);

     //some files might be stereo, so use mix channel
     fft.forward(player.mix);

     //since all files in the directory are true, write 1 before the FFT data
     fw.write("1 ");

     //go through FFT using loop
     for(int i = 0; i < fft.specSize(); i++)

      {
         //write FFT with band number in front of it, convert to dB
         fw.write((i + 1) + ":" + 20 * log( 2 * fft.getBand(i) / fft.timeSize() ) + " ");

     }

       //create new line to start next file data on
       fw.write("\n");
       //close the player to avoid running out of memory
       player.close();

  }


  }




  //close and flush writer when done
  print("Done Writing!");
  fw.close();
  fw.flush();

 }



catch (IOException e) 
{

}

//terminate program when done 
exit();
}
Tagged:

Answers

  • Try this modified example. It loads the wav files in your current data directory, then it traverses the list playing one by one ad saving the processed FFT data in your txt file.

    Kf

    //REFERENCE: https://forum.processing.org/two/discussion/23181/minim-fft-returning-zero-for-some-files#latest
    //REFERENCE: http://code.compartmental.net/minim/index.html
    
    import ddf.minim.analysis.*;
    import ddf.minim.*;
    import java.io.*;
    
    Minim       minim;
    AudioPlayer player;
    FFT         fft;
    FileWriter fw;
    String filePath;
    
    StringList fn=new StringList();
    int counter = 0;
    boolean loading=false;
    
    void setup() {
    
      filePath = dataPath("")+"\\"; 
    
      minim = new Minim(this);
      try { 
        //create .txt file to record data
        fw = new FileWriter(dataPath("")+"\\"+"audioRawData.txt");
        //run data() which reads .wav files and outputs FFT data to text file
      }
    
      catch (IOException e) {
      }
    
      loadFiles();  
      loadNext();
    }
    
    
    void draw() {
    
      if (loading==false) {
    
        //If done playing... play next
        if (player.isPlaying()==false) {
    
          if (counter==fn.size()-1) {
            finishNow();
          } else {      
            loadNext();
          }
        }
      }  
    
      dataSave();
    }
    
    
    void loadFiles() {
    
      //list files in a directory given by filePath  
      File[] files = new File(filePath).listFiles();
    
      //loop thru files
      for (File file : files) 
      {
        //get name of file
        String fileName = file.getName();
    
        //only process if .wav file
        if (fileName.contains(".wav"))
        {
    
          fn.append(fileName);
          println(fn.size()+"\t"+fileName);
        }
      }
    }
    
    void finishNow() {
    
      //close and flush writer when done
      try {
        print("Done Writing!");
        fw.close();
        fw.flush();
      }
      catch (IOException e) {
      }
    
      println("Normal termination....");
      exit();
    }
    
    
    void loadNext() {
    
      //Ensure draw doesn't access data while in loading stage. Maybe this is not needed.
      loading=true;
    
      println("Loading "+counter+" " +fn.get(counter));
    
      //If it was playing before... close it.
      if (player!=null) {
        player.close();
      }
    
      //load file in Minim and play using AudioPlayer
      player = minim.loadFile(filePath + fn.get(counter));
      player.play();
    
      //create new FFT and use Hamming window
      fft = new FFT(player.bufferSize(), player.sampleRate());
      fft.window(FFT.HAMMING);
    
      //some files might be stereo, so use mix channel
      fft.forward(player.mix);
      counter=(counter+1)%fn.size();
      dataMetaStamp();
      loading=false;
    }
    
    void dataMetaStamp() {
    
      try {
        //since all files in the directory are true, write 1 before the FFT data
        fw.write("METATAGE#"+counter+"\t"+fn.get(counter)+"\n");
      }
    
      catch (IOException e) {
      }
    }
    
    void dataSave() {
    
    
      try {
    
        //go through FFT using loop
        for (int i = 0; i < fft.specSize(); i++) {
    
          //write FFT with band number in front of it, convert to dB
          fw.write((i + 1) + ":" + 20 * log( 2 * fft.getBand(i) / fft.timeSize() ) + " ");
        }
    
        //create new line to start next file data on
        fw.write("\n");
      }
    
      catch (IOException e) {
      }
    }
    
  • Thanks for the answer, but some files are still returning zero for the FFT even though there is data in the .wav file. Half of the files I processed using your code still returned zero.

  • can you post one of the failing files, or a mp3 of it anyway because a wav will be too big.

    i have a feeling that you are using fft forward wrongly. you can't just call it once, needs to be once for each frame of the input. normally the draw() loop manages that, but you don't have a draw().

  • kf's is better because it is looping over the file. but it's doing it in realtime and i wonder if you can do better by not playing the file, just calling forward()

    either way i'm getting a file with lots of -Infinity in it 8(

  • As an exercise, you could check what FFT output gives you zero or infinity and then save that specific buffer into a csv for example. Even better, if you save the buffer and the FFT and then have a look at the data and make some sense of it. If you provide the files, I could do some R or octave magic.

    Kf

  • edited June 2017

    Hello, thanks for all your responses, but I found a fix by not using the AudioPlayer and instead using the AudioRecordingStream to load my data.

    I used this code: https://github.com/ddf/Minim/blob/master/examples/Analysis/offlineAnalysis/offlineAnalysis.pde

    I believe that the problem was something to do with the AudioPlayer loading my files wrong, but I'm still not 100% sure why the code didn't work.

Sign In or Register to comment.