Question

I am reading values from a wav file; selecting only some of those values and writing them into another wav file (inorder to remove silence periods from the wav file). The problem is, that when I am creating this new wav file, it has background noise (which is not present in the original wav file). I am adding here the part of the code which is doing the file writing part:

private void writeToFile(String filePath) {
        short nChannels = 1;
        int sRate = 16000;
        short bSamples = 16;
        audioShorts = new short[size];
        int nSamples = 0;
        for(int i=0; i<size-1; i++) {
            //audioShorts[i] = Short.reverseBytes((short)(zff[i]*0x8000));
            if(slope[i] >= slopeThreshold) { // Voice region -- Should be written to output
                audioShorts[nSamples] = Short.reverseBytes((short)(a[i]*0x8000));
                audioShorts[nSamples+1] = Short.reverseBytes((short)(a[i+1]*0x8000));
                nSamples += 2;
                i++;
            }
            /*else
                audioShorts[i] = 0;*/
        }
        finalShorts = new short[nSamples];
        for(int i=0; i<nSamples; i++){
            finalShorts[i] = audioShorts[i];
        }
        data = new byte[finalShorts.length*2];
        ByteBuffer buffer = ByteBuffer.wrap(data);
        ShortBuffer sbuf =  buffer.asShortBuffer();
        sbuf.put(finalShorts);
        data = buffer.array();
        Log.d("Data length------------------------------", Integer.toString(data.length));
        RandomAccessFile randomAccessWriter;
        try {
            randomAccessWriter = new RandomAccessFile(filePath, "rw");
            randomAccessWriter.setLength(0); // Set file length to 0, to prevent unexpected behaviour in case the file already existed
            randomAccessWriter.writeBytes("RIFF");
            randomAccessWriter.writeInt(Integer.reverseBytes(36+data.length)); // File length 
            randomAccessWriter.writeBytes("WAVE");
            randomAccessWriter.writeBytes("fmt ");
            randomAccessWriter.writeInt(Integer.reverseBytes(16)); // Sub-chunk size, 16 for PCM
            randomAccessWriter.writeShort(Short.reverseBytes((short) 1)); // AudioFormat, 1 for PCM
            randomAccessWriter.writeShort(Short.reverseBytes(nChannels));// Number of channels, 1 for mono, 2 for stereo
            randomAccessWriter.writeInt(Integer.reverseBytes(sRate)); // Sample rate
            randomAccessWriter.writeInt(Integer.reverseBytes(sRate*bSamples*nChannels/8)); // Byte rate, SampleRate*NumberOfChannels*BitsPerSample/8
            randomAccessWriter.writeShort(Short.reverseBytes((short)(nChannels*bSamples/8))); // Block align, NumberOfChannels*BitsPerSample/8
            randomAccessWriter.writeShort(Short.reverseBytes(bSamples)); // Bits per sample
            randomAccessWriter.writeBytes("data");
            randomAccessWriter.writeInt(Integer.reverseBytes(data.length)); // No. of samples
            randomAccessWriter.write(data);
            randomAccessWriter.close();

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
Was it helpful?

Solution

Your code snippet leaves some details out (like what slope and slopeThreshold are), so treat this answer as a suggestion only.

In general, this kind of chopping of audio data will introduce noise. It depends on where the cut happens. If the last sample before a cut is identical to the first one after it, you're safe, but otherwise you will introduce a click.

If the cuts are infrequent, you will be hearing individual clicks but if the chopping happens often enough, it might sound like continuous noise.

To do this without clicks, you would need to add a short fade out and fade in around each cut.

EDIT: try removing the "if (slope[i] >= slopeThreshold)" condition and see if the noise disappears. If so, the noise is very likely a result of what I described. Otherwise, you probably have some error with the various byte conversions.

OTHER TIPS

Instead of:

   data = new byte[finalShorts.length*2];
    ByteBuffer buffer = ByteBuffer.wrap(data);
    ShortBuffer sbuf =  buffer.asShortBuffer();
    sbuf.put(finalShorts);
    data = buffer.array();

would not it be necessary to convert from short [] to byte [] ?

data = shortToBytes(finalShorts);

public byte [] shortToBytes(short [] input){
  int short_index, byte_index;
  int iterations = input.length;

  byte [] buffer = new byte[input.length * 2];

  short_index = byte_index = 0;

  for(/*NOP*/; short_index != iterations; /*NOP*/)
  {
    buffer[byte_index]     = (byte) (input[short_index] & 0x00FF); 
    buffer[byte_index + 1] = (byte) ((input[short_index] & 0xFF00) >> 8);

    ++short_index; byte_index += 2;
  }

  return buffer;
}

This work for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top