Recognize wav files with silence in Java

861 Views Asked by At

I need a function in JAVA, something like this:

Input: .wav file (or byte[] fileBytes) Output: true/false (the file consists of silence only)

What is the best way to do it?

Thank you.

UPDATE:

  1. The command that I use for recording:

    arecord --format=S16_LE --max-file-time=60 --rate=16000 --file-type=wav randomvalue_i.wav

  2. Silent = no audio at all

3

There are 3 best solutions below

1
On BEST ANSWER

Well, the short answer is you'll want to scan the .WAV data and do a min/max value on it. A "silent" file the values should essentially all be 0.

The longer answer is that you'll want to understand the .WAV format, which you can find described here (http://soundfile.sapp.org/doc/WaveFormat/). You can probably skip over the first 44 bytes (RIFF, 'fmt') to get down to the data, then start looking at the bytes. The 'bits-per-sample' value from the header might be important, as 16-bit samples would mean you'd need to consolidate 2 'bytes' together to get a single sample. But, even so, both bytes would be 0 for a silent, 16-bit sample file. Ditto for NumChannels - in theory you should understand it, but again, both should be 0 for true 'silent'. If all the data is '0', it's silent.

"Silent" is a bit ambiguous. Above, I was strict and assumed it meant true '0' only. However, in a silent room, there would still be very low levels of background ambient noise. In that case, you'd need to be a bit more forgiving about the comparison. e.g. calculate a min/max for each sample, and insure that the range is within some tolerance. It can still be determined, but it just adds code.

For completeness:

public boolean isSilent(byte[] info) {
    for (int idx = 44; idx < info.length; ++idx) {
        if (info[idx] != 0)
            return false;
    }
    return true;
}
1
On

You could have a .wav file that is what you consider "silence" and compare it to the other .wav file to see if they have the same frequency.

1
On

i wrote a function which seems to do a really good job in detecting silence vs. non-silence:

 private boolean isSilent(byte[] byteArray) {
    IntBuffer intBuf = ByteBuffer.wrap(byteArray).order(ByteOrder.BIG_ENDIAN).asIntBuffer();
    int[] array = new int[intBuf.remaining()];
    intBuf.get(array);
    StandardDeviation sd = new StandardDeviation();
    double[] doubles = Arrays.stream(array).asDoubleStream().toArray();
    double stddev = sd.evaluate(doubles);
    logger.info("stddev: {}", stddev);
    return !(stddev > 10000000D);
}

basically analyzes the sound and if it finds small standard deviation moves, then it presumes it is "mostly" quiet, and if the stddev moves are larger, it presume that it is not silent. the differential between "silent" or "quiet" and ones with sound is fairly large. i found that a value of over around 10^6 or above is indicative of there being no silence in the audio clip.