javaarraysaudiooscilloscope

Java: Plotting Left and Right channels of a .flac audio file on an X-Y grid. (Oscilloscope)


I am trying to create an X-Y Oscilloscope in Java and I have gotten stuck. I have read through all the documentation for jFlac, the library i am using to decode my .flac audio file and the free lossless audio codec documentation here. I cannot seem to find the answer to the problem i am having. Please consider the following.

public void processPCM(ByteData pcm) {
    byte[] temp = pcm.getData();
    line.write(temp, 0, pcm.getLen());
    leftAndRight = new int[pcm.getData().length];
    for(int i = 0; i < temp.length; i+=2){
        leftAndRight[i/2] = (temp[i + 1]<<8) + (temp[i] & 0xff);
    }
}

This is where the sample data from my file is put into the SourceDataLine and is played. After i write the data to the line, i wish to convert the left and right audio into separate integer array variables x[] and y[], respectively.

This is the StreamInfo for the file i am using:

PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian

from the code above, pcm.getLen() returns a value of 16384 and pcm.getData() returns a byte array of length 90112. It's the data in this byte array, if I'm not mistaken, that i need to separate the left and right channels from, and then convert into integer arrays. This is the part that I do not understand how to accomplish.

Edit: I changed the above code to something i came across that i think might be how to get the byte array into an integer array, but i am still clueless to how the left and right channels are arranged.


Solution

  • Looking at the code in http://jflac.cvs.sourceforge.net/viewvc/jflac/jFLAC/src/java/org/kc7bfi/jflac/FLACDecoder.java?revision=1.13&view=markup it appears that the contents of the byte array are: a series of samples, each of which is: a series of channels, each of which is: a series of bytes representing one sample on one channel, least significant byte first. The value of getLen() is the number of valid bytes in it; there may be more data than that because the same ByteData object is reused, it may be overallocated to avoid repeated reallocation, etc.

    So, you'll want something like:

    byte[] data = pcm.getData();
    int n_bytes = pcm.getLen();
    int n_samples = n_bytes / (n_channels*bytes_per_sample);
    int k=0;
    for (int i=0; i<n_samples; ++i) {
      for (int j=0; j<n_channels; ++j) {
        output[j][i] = data[k] + (data[k+1)<<8);
        k += 2;
      }
    }
    

    (warning: code has not been tested and may consist entirely of syntax errors and bugs, but hopefully the idea is clear enough).