I am trying to extract amplitude array from an audio file(WAV file). I will be using this amplitude array to plot amplitude vs time graph for the given wav file. I am able to plot the graph myself but does not know how to extract the amplitude from given audio(wav) file in java?
2 Answers
Here is a helper class that you can use. The getSampleInt()
method is what you need to get the amplitude:
File file = ...;
WavFile wav = new WavFile(file);
int amplitudeExample = wav.getSampleInt(140); // 140th amplitude value.
for (int i = 0; i < wav.getFramesCount(); i++) {
int amplitude = wav.getSampleInt(i);
// Plot.
}
It also can play files so that you can test it, but only 8bit, or 16bit files. For other cases you can only read them.
Also, please look at these diagrams to see what WAV files consist of and better understand what this class does.
public class WaveFile {
public final int NOT_SPECIFIED = AudioSystem.NOT_SPECIFIED; // -1
public final int INT_SIZE = 4;
private int sampleSize = NOT_SPECIFIED;
private long framesCount = NOT_SPECIFIED;
private int sampleRate = NOT_SPECIFIED;
private int channelsNum;
private byte[] data; // wav bytes
private AudioInputStream ais;
private AudioFormat af;
private Clip clip;
private boolean canPlay;
public WaveFile(File file) throws UnsupportedAudioFileException, IOException {
if (!file.exists()) {
throw new FileNotFoundException(file.getAbsolutePath());
}
ais = AudioSystem.getAudioInputStream(file);
af = ais.getFormat();
framesCount = ais.getFrameLength();
sampleRate = (int) af.getSampleRate();
sampleSize = af.getSampleSizeInBits() / 8;
channelsNum = af.getChannels();
long dataLength = framesCount * af.getSampleSizeInBits() * af.getChannels() / 8;
data = new byte[(int) dataLength];
ais.read(data);
AudioInputStream aisForPlay = AudioSystem.getAudioInputStream(file);
try {
clip = AudioSystem.getClip();
clip.open(aisForPlay);
clip.setFramePosition(0);
canPlay = true;
} catch (LineUnavailableException e) {
canPlay = false;
System.out.println("I can play only 8bit and 16bit music.");
}
}
public boolean isCanPlay() {
return canPlay;
}
public void play() {
clip.start();
}
public void stop() {
clip.stop();
}
public AudioFormat getAudioFormat() {
return af;
}
public int getSampleSize() {
return sampleSize;
}
public double getDurationTime() {
return getFramesCount() / getAudioFormat().getFrameRate();
}
public long getFramesCount() {
return framesCount;
}
/**
* Returns sample (amplitude value). Note that in case of stereo samples
* go one after another. I.e. 0 - first sample of left channel, 1 - first
* sample of the right channel, 2 - second sample of the left channel, 3 -
* second sample of the rigth channel, etc.
*/
public int getSampleInt(int sampleNumber) {
if (sampleNumber < 0 || sampleNumber >= data.length / sampleSize) {
throw new IllegalArgumentException(
"sample number can't be < 0 or >= data.length/"
+ sampleSize);
}
byte[] sampleBytes = new byte[4]; //4byte = int
for (int i = 0; i < sampleSize; i++) {
sampleBytes[i] = data[sampleNumber * sampleSize * channelsNum + i];
}
int sample = ByteBuffer.wrap(sampleBytes)
.order(ByteOrder.LITTLE_ENDIAN).getInt();
return sample;
}
public int getSampleRate() {
return sampleRate;
}
public Clip getClip() {
return clip;
}
}

- 4,087
- 1
- 27
- 33
-
what's the difference between 8-bit,16 bit sample size...i am using 24 bit audio...how to modify the code for 24 bit audio? and it also gives line unavailable exception....and please could you explain the code in detail...i am new to this audio api and audio thing... PS:Thanks a lot – Jason Sep 11 '16 at 09:45
-
@Jason it's a quality. You should read what WAV is, before trying to read it :) Google, or post another question here. I've deleted a few redundant lines from my example - can read any WAV file, but don't try playing anything other than 8bit or 16bit. Java doesn't support this, you can only read them and plot the graphic as you wanted. – Artem Novikov Sep 11 '16 at 17:31
-
the same code can't be used for mp3 file?...coz of different formats – Jason Sep 12 '16 at 13:45
-
Unfortunately, Java doesn't support mp3 out of the box. Try MP3 SPI library. It's said it's enough to add it to the classpath and Java will start recognizing mp3 files (so you'll be able to use my example). http://www.javazoom.net/mp3spi/documents.html – Artem Novikov Sep 12 '16 at 15:53
-
The imports would sure help – Steve Owens Oct 17 '20 at 23:16
-
Shouldn't the data length be calculated as `frameCount * frameSize * channelNums` as the `frameSize` is the size bits of each frame, replacing the `sampleSize` which counts the size bits of each sample? – Zukaru Oct 10 '21 at 06:26
I tried your code and with a few minor changes it created a result. Whats wrong with the data the code puts out?
I Changed the following lines:
// create file input stream
DataInputStream fis = new DataInputStream(new FileInputStream(wavFile));
// create byte array from file
arrFile = new byte[(int) wavFile.length()];
fis.readFully(arrFile); // make sure you always read the full file, you did not check its return value, so you might be missing some data
The second thing I changed was:
System.out.println(Arrays.toString(s.extractAmplitudeFromFile(f)));
In your Main method, since you were only printing out the adress of the arary. After those changes the code put out an array that had values, that seemed to correlate with the desired data.
what excatly are you missing, or what do you expect of the data? Could you please clarify the question a bit more?

- 222
- 1
- 5
-
what i want to do is plot a graph between amplitude and time for a particular wav file....the time is related to the moment/current time of the audio wav file being played.....so how can i extract amplitude from wav file at different moments? PS: Please ignore my code....i don't think it might be correct – Jason Sep 07 '16 at 16:29
-
actually, the code worked pretty decent. Why did you remove it? You received an array containing integers. Those are the amplitude values. the time is known because of the sampling rate. you can extract it from the audioformat object. its given in hz, say you have 44100, means 44100 values of the array are 1 second. thats how you calculate the time for a sample – Melv_80 Sep 08 '16 at 07:20
-
I tested the code you posted previously with a PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian WAV file of windows (ir_begin.wav), it gave me the correct values – Melv_80 Sep 08 '16 at 07:24