Java extract amplitude array from recorded wave

转载自: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.)

原文地址:https://www.cnblogs.com/passedbylove/p/11888799.html