Re De Pasquale
Re De Pasquale

Reputation: 108

Plot audio waveform graph Java

I want to plot a graph of waveform from an .wav audio file. I find in this site a function that extract byte of a .wav:

ByteArrayOutputStream out = new ByteArrayOutputStream();
BufferedInputStream in = null;
try {
    in = new BufferedInputStream(new FileInputStream(args[0]));
} catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

int read;
byte[] buff = new byte[1024];
while ((read = in.read(buff)) > 0)
{
    out.write(buff, 0, read);
}
out.flush();

byte[] audioBytes = out.toByteArray();
for (int i=0; i<audioBytes.length; i++) {
    System.out.println(audioBytes[i]);
}

Then I use the points that I found in console (System.out...) to plot my audio waveform in "Microsoft Excel" and the risult is:

waveform on Excel BUT this waveform of my .wav file is a lot different from the waveform that plots (i.e.) open source "Praat" :

waveform on Praat Where I wrong? Not are the bytes of file that I must take?

Upvotes: 2

Views: 2429

Answers (2)

Margherita
Margherita

Reputation: 158

In the array "result" there are the point that you would find.

public double[] extract(File inputFile) {
        AudioInputStream in = null;
        try {
            in = AudioSystem.getAudioInputStream(inputFile);
        } catch (Exception e) {
            System.out.println("Cannot read audio file");
            return new double[0];
        }
        AudioFormat format = in.getFormat();
        byte[] audioBytes = readBytes(in);

        int[] result = null;
        if (format.getSampleSizeInBits() == 16) {
            int samplesLength = audioBytes.length / 2;
            result = new int[samplesLength];
            if (format.isBigEndian()) {
                for (int i = 0; i < samplesLength; ++i) {
                    byte MSB = audioBytes[i * 2];
                    byte LSB = audioBytes[i * 2 + 1];
                    result[i] = MSB << 8 | (255 & LSB);
                }
            } else {
                for (int i = 0; i < samplesLength; i += 2) {
                    byte LSB = audioBytes[i * 2];
                    byte MSB = audioBytes[i * 2 + 1];
                    result[i / 2] = MSB << 8 | (255 & LSB);
                }
            }
        } else {
            int samplesLength = audioBytes.length;
            result = new int[samplesLength];
            if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
                for (int i = 0; i < samplesLength; ++i) {
                    result[i] = audioBytes[i];
                }
            } else {
                for (int i = 0; i < samplesLength; ++i) {
                    result[i] = audioBytes[i] - 128;
                }
            }
        }

        return result;
    }

Upvotes: 4

Peter
Peter

Reputation: 847

It seems you are assuming that each byte in the file is representing the amplitude of the wave at the next point in time. This is (generally speaking) not case. Apart from the fact that the file starts with a header, each samples consists of a number of channels and within each channel, a sample might occupy less (e.g. 4 bits or more (e.g. 16 bits) space than just one byte. See for example this explanation: http://www.topherlee.com/software/pcm-tut-wavformat.html.

Upvotes: 0

Related Questions