转载自:http://ganeshtiwaridotcomdotnp.blogspot.com/2011/12/java-extract-amplitude-array-from.html
Extract amplitude array from recorded/saved wav : From File , AudioInputStream , ByteArray of File or ByteArrayInputStream - working java source code example
import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; /** * saving and extracting amplitude data from wavefile byteArray * * @author Ganesh Tiwari */ public class WaveData { private byte[] arrFile; private byte[] audioBytes; private int[] audioData; private ByteArrayInputStream bis; private AudioInputStream audioInputStream; private AudioFormat format; private double durationSec; private double durationMSec; public WaveData() { } public int[] extractAmplitudeFromFile(File wavFile) { try { // create file input stream FileInputStream fis = new FileInputStream(wavFile); // create bytearray from file arrFile = new byte[(int) wavFile.length()]; fis.read(arrFile); } catch (Exception e) { System.out.println("SomeException : " + e.toString()); } return extractAmplitudeFromFileByteArray(arrFile); } public int[] extractAmplitudeFromFileByteArray(byte[] arrFile) { // System.out.println("File : "+wavFile+""+arrFile.length); bis = new ByteArrayInputStream(arrFile); return extractAmplitudeFromFileByteArrayInputStream(bis); } /** * for extracting amplitude array the format we are using :16bit, 22khz, 1 * channel, littleEndian, * * @return PCM audioData * @throws Exception */ public int[] extractAmplitudeFromFileByteArrayInputStream(ByteArrayInputStream bis) { try { audioInputStream = AudioSystem.getAudioInputStream(bis); } catch (UnsupportedAudioFileException e) { System.out.println("unsupported file type, during extract amplitude"); e.printStackTrace(); } catch (IOException e) { System.out.println("IOException during extracting amplitude"); e.printStackTrace(); } // float milliseconds = (long) ((audioInputStream.getFrameLength() * // 1000) / audioInputStream.getFormat().getFrameRate()); // durationSec = milliseconds / 1000.0; return extractAmplitudeDataFromAudioInputStream(audioInputStream); } public int[] extractAmplitudeDataFromAudioInputStream(AudioInputStream audioInputStream) { format = audioInputStream.getFormat(); audioBytes = new byte[(int) (audioInputStream.getFrameLength() * format.getFrameSize())]; // calculate durations durationMSec = (long) ((audioInputStream.getFrameLength() * 1000) / audioInputStream.getFormat().getFrameRate()); durationSec = durationMSec / 1000.0; // System.out.println("The current signal has duration "+durationSec+" Sec"); try { audioInputStream.read(audioBytes); } catch (IOException e) { System.out.println("IOException during reading audioBytes"); e.printStackTrace(); } return extractAmplitudeDataFromAmplitudeByteArray(format, audioBytes); } public int[] extractAmplitudeDataFromAmplitudeByteArray(AudioFormat format, byte[] audioBytes) { // convert // TODO: calculate duration here audioData = null; if (format.getSampleSizeInBits() == 16) { int nlengthInSamples = audioBytes.length / 2; audioData = new int[nlengthInSamples]; if (format.isBigEndian()) { for (int i = 0; i < nlengthInSamples; i++) { /* First byte is MSB (high order) */ int MSB = audioBytes[2 * i]; /* Second byte is LSB (low order) */ int LSB = audioBytes[2 * i + 1]; audioData[i] = MSB << 8 | (255 & LSB); } } else { for (int i = 0; i < nlengthInSamples; i++) { /* First byte is LSB (low order) */ int LSB = audioBytes[2 * i]; /* Second byte is MSB (high order) */ int MSB = audioBytes[2 * i + 1]; audioData[i] = MSB << 8 | (255 & LSB); } } } else if (format.getSampleSizeInBits() == 8) { int nlengthInSamples = audioBytes.length; audioData = new int[nlengthInSamples]; if (format.getEncoding().toString().startsWith("PCM_SIGN")) { // PCM_SIGNED for (int i = 0; i < audioBytes.length; i++) { audioData[i] = audioBytes[i]; } } else { // PCM_UNSIGNED for (int i = 0; i < audioBytes.length; i++) { audioData[i] = audioBytes[i] - 128; } } }// end of if..else // System.out.println("PCM Returned===============" + // audioData.length); return audioData; } public byte[] getAudioBytes() { return audioBytes; } public double getDurationSec() { return durationSec; } public double getDurationMiliSec() { return durationMSec; } public int[] getAudioData() { return audioData; } public AudioFormat getFormat() { return format; } }
留言:
Think I found a bug for 8 bit unsigned samples in the code above.
Java regards a byte-variable as a signed variable, so we can't just subtract 128 for all sample-values. For "negative" values we must instead add 128, I think.
E.g. the sampled unsigned value 10000000 (128 unsigned) should mean that we are in the middle of the value-range. It should actually mean 0, but java sees it as -128, and if we subtract 128 we'll get -256, which isn't what we want at all.
And the "highest" sample-value possible with 8 bits, 11111111, means -1 to java if it's in a byte-variable. We'd get the value -129 here with the old method, but we would expect 127.
For all "positive" values 00000000 - 01111111 it works fine to subtract 128 as before, so something like this would work better:
// PCM_UNSIGNED
for (int i = 0; i < audioBytes.length; i++)
{
if (audioBytes[i] >= 0)
_audioData[i] = audioBytes[i] - 128;
else
_audioData[i] = audioBytes[i] + 128;
}
(Or e.g. you could "shift" the byte-value into an int-variable before subtracting 128.)