Loading...
Logo
Processing Forum
Can't seem to get my head around this: trying to read a binary file (in this case a .wav file) in, 4 bytes at a time.  Ultimately I'd like to stream sample by sample through the file; I've done this with the Ess library but I'd like something a bit faster and more robust.

My research is leading towards using a FileInputStream, but I can't get the syntax right.  Anyone have a bit of code to point me in the right direction?

Here's the .wav format, if that's any help:
http://www.sonicspot.com/guide/wavefiles.html#data

Thanks!

Replies(4)

" I can't get the syntax right"
In general, we ask to see your best attempt...
But I will just paste a code fragment of one of my programs, hopefully, it can get you started.
Copy code
  1.     final int BUFFER_SIZE = 4096; // You can adjust this
  2.     String fileNameIn = "G:/Tmp/LargeImage.jpg";

  3.     byte[] buffer = new byte[BUFFER_SIZE];
  4.     InputStream in = null;
  5.     try
  6.     {
  7.       in = new BufferedInputStream(new FileInputStream(fileNameIn));
  8.       int n = in.read(buffer, 0, BUFFER_SIZE);
  9.       while (n > 0)
  10.       {
  11.         // Use buffer here
  12.         n = in.read(buffer, 0, BUFFER_SIZE);
  13.       }
  14.     }
  15.     catch (IOException e)
  16.     {
  17.       System.out.println("Error: " + e);
  18.     }
  19.     finally
  20.     {
  21.       try
  22.       {
  23.         if (in != null)
  24.           in.close();
  25.       }
  26.       catch (IOException e)
  27.       {
  28.         System.out.println("Error on close: " + e);
  29.       }
  30.     }

Thanks phi.lho, I would have posted code but was going in so many different directions I didn't know what would be helpful.  Trying your example, I get the same issue as from my code: it seems to read in fine but it only returns the buffer size as an int (in your example 4096, in mine 4).

Here's my code:
Copy code
  1. String filename = "/Users/jeffthompson/Documents/Processing/ReadBinaryFile/data/test-1min.wav";
    BufferedInputStream s;
    byte[] buffer = new byte[4];

    void setup() {

      try {
        s = new BufferedInputStream(new FileInputStream(filename));
        int bytesRead = 0;  

        while ( (bytesRead = s.read (buffer)) != -1) {    // so long as we haven't reached the end of the file (-1)
          println(bytesRead);
        }
      }
      catch (IOException e) {
        println("ERROR!");
      }

      exit();
    }
The first four bytes of a .wav file should be (when converted to ASCII) "RIFF".  Should be 52 49 46 46 in hex.

Here's a "Processing-ified" version of your code:

Copy code
  1. final int BUFFER_SIZE = 4;

    String fileNameIn = "/Users/jeffthompson/Documents/Processing/ReadBinaryFile/data/test-1min.wav";
    byte[] buffer = new byte[BUFFER_SIZE];
    InputStream in = null;

    void setup() {

      try {
        in = new BufferedInputStream(new FileInputStream(fileNameIn));
        int n = in.read(buffer, 0, BUFFER_SIZE);

        // read in 4 bytes
        n = in.read(buffer, 0, BUFFER_SIZE);
        println(n);  // print the data
        in.close();
      }
      catch (IOException e) {
        System.out.println("Error: " + e);
      }
      finally {
        try {
          if (in != null) {
            in.close();
          }
        }
        catch (IOException e) {
          System.out.println("Error on close: " + e);
        }
      }
     
      exit();
    }
When printing the result I get 4.

I have a feeling that I'm misunderstanding how this all works - BufferedReaders make a lot of sense but reading binary files... I just can't quite get it.

Ok, I can get it to return the correct hex values and it seems to work great:

Copy code
  1. // file to load
    String filename = "/Users/jeffthompson/Documents/Processing/ReadBinaryFile/data/test-1min.wav";
    int chunksToRead;                      // how many chunks to read out
    int bufferSize = 4;                    // how many bytes to load at a time (.wav is 4-byte chunks)

    byte[] buffer = new byte[bufferSize];  // read values into this buffer
    int tempVal;                           // temporary value to store incoming data
    InputStream input = null;              // stream itself (to input data from file)


    void setup() {

      // open stream
      try {
        input = new BufferedInputStream(new FileInputStream(filename));  // start stream
      }
      catch (IOException e) {
        println("Error: " + e);  // let us know if there are problems...
      }

      for (int i=0; i<chunksToRead; i++) {
        try {
          int n = input.read(buffer, 0, bufferSize);  // where to read from, offset, how many bytes
        }

        // if we have any errors, close and give us details
        catch (IOException e) {
          println("Error: " + e);
        }

        // read the data back
        // http://stackoverflow.com/questions/1026761/how-to-convert-a-byte-array-to-its-numeric-value-java
        for (int j=0; j<bufferSize; j++) {
          print(hex(buffer[j]) + " ");
          tempVal += (buffer[j] & 0xff) << (bufferSize * j);          // least significant byte first
          // tempVal = (tempVal << bufferSize) + (buffer[j] & 0xff);  // most significant byte first
        }
        println("= " + tempVal);                                      // display the values
        tempVal = 0;                                                  // reset value
      }

      // quit when done
      try {
        input.close();             // close the stream first...
      }
      catch (IOException e) {
        println("Error closing stream: " + e);   
      }
      exit();
    }
However, I can't seem to get the byte array to cast into an integer value that seems correct.  Various online calculators and sources don't give results that agree.

I found this via StackOverflow for Little Endian (wav format):
Copy code
  1. tempVal += (buffer[j] & 0xff) << (bufferSize * j);
But the values returned are often too large for the .wav format.  Any suggestions?
Shouldn't it be tempVal += (buffer[j] & 0xff) << (8 * j);?