Question

How can I detect silence when recording operation is started in Java? What is PCM data? How can I calculate PCM data in Java?

I found the solution :

package bemukan.voiceRecognition.speechToText;

import javax.sound.sampled.*;
import java.io.*;

public class RecordAudio {
    private File audioFile;
    protected boolean running;
    private ByteArrayOutputStream out;
    private AudioInputStream inputStream;
    final static float MAX_8_BITS_SIGNED = Byte.MAX_VALUE;
    final static float MAX_8_BITS_UNSIGNED = 0xff;
    final static float MAX_16_BITS_SIGNED = Short.MAX_VALUE;
    final static float MAX_16_BITS_UNSIGNED = 0xffff;
    private AudioFormat format;
    private float level;
    private int frameSize;

    public RecordAudio(){
         getFormat();
    }

    private AudioFormat getFormat() {
        File file = new File("src/Facebook/1.wav");
        AudioInputStream stream;
        try {
            stream = AudioSystem.getAudioInputStream(file);
            format=stream.getFormat();
            frameSize=stream.getFormat().getFrameSize();
            return stream.getFormat();
        } catch (UnsupportedAudioFileException e) {

        } catch (IOException e) {

        }
        return null;
    }

    public void stopAudio() {

        running = false;
    }

    public void recordAudio() {

        try {
            final AudioFormat format = getFormat();
            DataLine.Info info = new DataLine.Info(
                    TargetDataLine.class, format);
            final TargetDataLine line = (TargetDataLine)
                    AudioSystem.getLine(info);
            line.open(format);
            line.start();
            Runnable runner = new Runnable() {
                int bufferSize = (int) format.getSampleRate()
                        * format.getFrameSize();
                byte buffer[] = new byte[bufferSize];

                public void run() {
                     int readPoint = 0;

                    out = new ByteArrayOutputStream();
                    running = true;
                     int sum=0;
                    while (running) {
                        int count =
                              line.read(buffer, 0, buffer.length);
                              calculateLevel(buffer,0,0);
                         System.out.println(level);

                        if (count > 0) {
                            out.write(buffer, 0, count);
                        }
                    }
                    line.stop();
                }
            };
            Thread captureThread = new Thread(runner);
            captureThread.start();
        } catch (LineUnavailableException e) {
            System.err.println("Line unavailable: " + e);
            System.exit(-2);
        }
    }

    public File getAudioFile() {
        byte[] audio = out.toByteArray();
        InputStream input = new ByteArrayInputStream(audio);
        try {

            final AudioFormat format = getFormat();
            final AudioInputStream ais =
                    new AudioInputStream(input, format,
                            audio.length / format.getFrameSize());
            AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("temp.wav"));
            input.close();
            System.out.println("New file created!");
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        return new File("temp.wav");
    }
    private void calculateLevel (byte[] buffer,
                                 int readPoint,
                                 int leftOver) {
        int max = 0;
        boolean use16Bit = (format.getSampleSizeInBits() == 16);
        boolean signed = (format.getEncoding() ==
                          AudioFormat.Encoding.PCM_SIGNED);
        boolean bigEndian = (format.isBigEndian());
        if (use16Bit) {
            for (int i=readPoint; i<buffer.length-leftOver; i+=2) {
                int value = 0;
                // deal with endianness
                int hiByte = (bigEndian ? buffer[i] : buffer[i+1]);
                int loByte = (bigEndian ? buffer[i+1] : buffer [i]);
                if (signed) {
                    short shortVal = (short) hiByte;
                    shortVal = (short) ((shortVal << 8) | (byte) loByte);
                    value = shortVal;
                } else {
                    value = (hiByte << 8) | loByte;
                }
                max = Math.max(max, value);
            } // for
        } else {
            // 8 bit - no endianness issues, just sign
            for (int i=readPoint; i<buffer.length-leftOver; i++) {
                int value = 0;
                if (signed) {
                    value = buffer [i];
                } else {
                    short shortVal = 0;
                    shortVal = (short) (shortVal | buffer [i]);
                    value = shortVal;
                }
                max = Math.max (max, value);
            } // for
        } // 8 bit
        // express max as float of 0.0 to 1.0 of max value
        // of 8 or 16 bits (signed or unsigned)
        if (signed) {
            if (use16Bit) { level = (float) max / MAX_16_BITS_SIGNED; }
            else { level = (float) max / MAX_8_BITS_SIGNED; }
        } else {
            if (use16Bit) { level = (float) max / MAX_16_BITS_UNSIGNED; }
            else { level = (float) max / MAX_8_BITS_UNSIGNED; }
        }
    } // calculateLevel


}
Was it helpful?

Solution

How can I detect silence when recording operation is started in Java?

Calculate the dB or RMS value for a group of sound frames and decide at what level it is considered to be 'silence'.

What is PCM data?

Data that is in Pulse-code modulation format.

How can I calculate PCM data in Java?

I do not understand that question. But guessing it has something to do with the speech-recognition tag, I have some bad news. This might theoretically be done using the Java Speech API. But there are apparently no 'speech to text' implementations available for the API (only 'text to speech').


I have to calculate rms for speech-recognition project. But I do not know how can I calculate in Java.

For a single channel that is represented by signal sizes in a double ranging from -1 to 1, you might use this method.

/** Computes the RMS volume of a group of signal sizes ranging from -1 to 1. */
public double volumeRMS(double[] raw) {
    double sum = 0d;
    if (raw.length==0) {
        return sum;
    } else {
        for (int ii=0; ii<raw.length; ii++) {
            sum += raw[ii];
        }
    }
    double average = sum/raw.length;

    double sumMeanSquare = 0d;
    for (int ii=0; ii<raw.length; ii++) {
        sumMeanSquare += Math.pow(raw[ii]-average,2d);
    }
    double averageMeanSquare = sumMeanSquare/raw.length;
    double rootMeanSquare = Math.sqrt(averageMeanSquare);

    return rootMeanSquare;
}

There is a byte buffer to save input values from the line, and what I should have to do with this buffer?

If using the volumeRMS(double[]) method, convert the byte values to an array of double values ranging from -1 to 1. ;)

OTHER TIPS

You need to catch the value like a number silence is zero or near

Please adapt your code to your requirement!!! In this case a variable named UMBRAL (Threshold in spanish)...

Suppose that you have access to WAV file like bytes ByteHeader...

private Integer Byte2PosIntBig(byte Byte24, byte Byte16, byte Byte08, byte Byte00) {
    return new Integer (
            ((Byte24) << 24)|
            ((Byte16 & 0xFF) << 16)|
            ((Byte08 & 0xFF) << 8)|
            ((Byte00 & 0xFF) << 0));
} 

Before ....

    RandomAccessFile RAFSource = new RandomAccessFile("your old file wav", "r");

Begins here...

int PSData = 44;
byte[] Bytes = new byte[4];
byte[] ByteHeader = new byte[44];
RAFSource.seek(0);
RAFSource.read(ByteHeader);

int WavSize = Byte2PosIntBig(ByteHeader[43],ByteHeader[42],ByteHeader[41],ByteHeader[40]);

int NumBits = Byte2PosIntBig(ByteHeader[35],ByteHeader[34]);
int NumByte = NumBits/8;

    for (int i = PSData;i < PSData+WavSize;i+=NumByte) {
      int WavSample = 0;
      int WavResultI =0;
      int WavResultO = 0;
      if (NumByte == 2) {

          RAFSource.seek(i);
          Bytes[0] = RAFSource.readByte();
          Bytes[1] = RAFSource.readByte();
          WavSample = (int)(((Bytes[1]) << 8)|((Bytes[0] & 0xFF) << 0));
          if (Math.abs(WavSample) < UMBRAL) {
            //SILENCE DETECTED!!!
          }

      } else {
        RAFSource.seek(i);
        WavSample = (short)(RAFSource.readByte() & 0xFF);
        short sSamT = (short)WavSample;
        sSamT += 128;
        double dSamD = (double)sSamT*Multiplier;
        if ((double)sSamT < UMBRAL) {
          //SILENCE DETECTED!!!
        }
      }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top