如何在混合后从.wav文件中删除噪音?

时间:2013-05-29 09:29:30

标签: java android audio wav

我已阅读this link的手册,但仍无法解决您的问题。

使用代码混合两个wav文件后,我得到一个wav文件(sdcard上的music.wav),但将其播放为 noise 。我真的不知道如何从music.wav文件中删除它。这对我来说是个难题。

这是我的源代码:

    public class MainActivity extends Activity {

public static final int FREQUENCY = 44100;
private InputStream in1, in2;
private byte[] output;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    try {
        mixSound();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private void mixSound() throws IOException {
//  AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, 44100, AudioTrack.MODE_STREAM);

    in1 = getResources().openRawResource(R.raw.media_b);
    in2 = getResources().openRawResource(R.raw.media_c);

    byte[] arrayMusic1 = null;
    arrayMusic1 = new byte[in1.available()];
    arrayMusic1 = createMusicArray(in1);
    in1.close();

    byte[] arrayMusic2 = null;
    arrayMusic2 = new byte[in2.available()];
    arrayMusic2 = createMusicArray(in2);
    in2.close();

    output = new byte[arrayMusic1.length];

    /** old
    audioTrack.play();  
    */

    for (int i = 0; i < output.length; i++) {
        float samplef1 = arrayMusic1[i] / 128.0f; 
        float samplef2 = arrayMusic2[i] / 128.0f;
        float mixed    = samplef1 + samplef2;

        // reduce the volume a bit:
        mixed *= 0.8;
        // hard clipping
        if (mixed > 1.0f)  mixed = 1.0f;
        if (mixed < -1.0f) mixed = -1.0f;

        byte outputSample  = (byte) (mixed * 128.0f);
        output[i]          = outputSample;  
    }

    /** old
    audioTrack.write(output, 0, output.length);
    convertByteToFile(output);
    save();  
    */
    saveToFile();
}

public static byte[] createMusicArray(InputStream is) throws IOException {

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    //10*1024 = 10KB
    byte[] byteBuffer   = new byte[10*1024]; 

    int i = Integer.MAX_VALUE;
    while ((i = is.read(byteBuffer, 0, byteBuffer.length)) > 0) {
        baos.write(byteBuffer, 0, i);
    }

    return baos.toByteArray(); 
}


/**
 * .WAV
 * more info --> https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

 The canonical WAVE format starts with the RIFF header:
 | FILE OFFSET | FIELD SIZE | FIELD NAME    
        0         4   ChunkID          Contains the letters "RIFF" in ASCII form
                                       (0x52494646 big-endian form).
        4         4   ChunkSize        36 + SubChunk2Size, or more precisely:
                                       4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
                                       This is the size of the rest of the chunk 
                                       following this number.  This is the size of the 
                                       entire file in bytes minus 8 bytes for the
                                       two fields not included in this count:
                                       ChunkID and ChunkSize.
        8         4   Format           Contains the letters "WAVE"
                                       (0x57415645 big-endian form).

        The "WAVE" format consists of two subchunks: "fmt " and "data":
        The "fmt " subchunk describes the sound data's format:

        12        4   Subchunk1ID      Contains the letters "fmt "
                                       (0x666d7420 big-endian form).
        16        4   Subchunk1Size    16 for PCM.  This is the size of the
                                       rest of the Subchunk which follows this number.
        20        2   AudioFormat      PCM = 1 (i.e. Linear quantization)
                                       Values other than 1 indicate some 
                                       form of compression.
        22        2   NumChannels      Mono = 1, Stereo = 2, etc.
        24        4   SampleRate       8000, 44100, etc.
        28        4   ByteRate         == SampleRate * NumChannels * BitsPerSample/8
        32        2   BlockAlign       == NumChannels * BitsPerSample/8
                                       The number of bytes for one sample including
                                       all channels. I wonder what happens when
                                       this number isn't an integer?
        34        2   BitsPerSample    8 bits = 8, 16 bits = 16, etc.
                  2   ExtraParamSize   if PCM, then doesn't exist
                  X   ExtraParams      space for extra parameters

        The "data" subchunk contains the size of the data and the actual sound:

        36        4   Subchunk2ID      Contains the letters "data"
                                       (0x64617461 big-endian form).
        40        4   Subchunk2Size    == NumSamples * NumChannels * BitsPerSample/8
                                       This is the number of bytes in the data.
                                       You can also think of this as the size
                                       of the read of the subchunk following this 
                                       number.
        44        *   Data             The actual sound data.

 */
public void saveToFile() {
    try {
        long mySubChunk1Size = 16;
        int myBitsPerSample  = 16;
        int myFormat         = 1;
        long myChannels      = 2;
        long mySampleRate    = 44100;
        long myByteRate      = mySampleRate * myChannels * (myBitsPerSample/8);
        int myBlockAlign     = (int) (myChannels * myBitsPerSample/8);

        long myDataSize      = output.length;
        long myChunk2Size    = myDataSize * myChannels * myBitsPerSample/8;
        long myChunkSize     = 36 + myChunk2Size;

        OutputStream os = new FileOutputStream(new File(Environment.getExternalStorageDirectory().getPath()+"/videokit/mixed.wav"));
        BufferedOutputStream bos = new BufferedOutputStream(os);
        DataOutputStream outFile = new DataOutputStream(bos);

        outFile.writeBytes("RIFF");                                     // 00 - RIFF
        outFile.write(intToByteArray((int)myChunkSize), 0, 4);          // 04 - how big is the rest of this file?
        outFile.writeBytes("WAVE");                                     // 08 - WAVE
        outFile.writeBytes("fmt ");                                     // 12 - fmt 
        outFile.write(intToByteArray((int)mySubChunk1Size), 0, 4);      // 16 - size of this chunk
        outFile.write(shortToByteArray((short)myFormat), 0, 2);         // 20 - what is the audio format? 1 for PCM = Pulse Code Modulation
        outFile.write(shortToByteArray((short)myChannels), 0, 2);       // 22 - mono or stereo? 1 or 2?  (or 5 or ???)
        outFile.write(intToByteArray((int)mySampleRate), 0, 4);         // 24 - samples per second (numbers per second)
        outFile.write(intToByteArray((int)myByteRate), 0, 4);           // 28 - bytes per second
        outFile.write(shortToByteArray((short)myBlockAlign), 0, 2);     // 32 - # of bytes in one sample, for all channels
        outFile.write(shortToByteArray((short)myBitsPerSample), 0, 2);  // 34 - how many bits in a sample(number)?  usually 16 or 24
        outFile.writeBytes("data");                                     // 36 - data
        outFile.write(intToByteArray((int)myDataSize), 0, 4);           // 40 - how big is this data chunk
        outFile.write(output);                                          // 44 - the actual data itself - just a long string of numbers

        outFile.flush();
        outFile.close();

    } catch (IOException e) {
        e.printStackTrace();
    }

}


 public static byte[] getBytesFromFile(File file) throws IOException {
     InputStream is = new FileInputStream(file);

     long length = file.length();
     if (length > Integer.MAX_VALUE) {
     }

     byte[] bytes = new byte[(int)length];
     int offset   = 0;
     int numRead  = 0;
     while (offset < bytes.length && (numRead = is.read(bytes, offset, Math.min(bytes.length - offset, 512*1024))) >= 0) {
             offset += numRead;
     }

     if (offset < bytes.length) {
         Log.i("xxx", "Could not completely read file");
     }
     is.close();

     return bytes;
}


private static byte[] intToByteArray(int i) {
    byte[] b = new byte[4];
    b[0]     = (byte) (i & 0x00FF);
    b[1]     = (byte) ((i >> 8)  & 0x000000FF);
    b[2]     = (byte) ((i >> 16) & 0x000000FF);
    b[3]     = (byte) ((i >> 24) & 0x000000FF);
    return b;
}

public static byte[] shortToByteArray(short data) {
        return new byte[]{(byte)(data & 0xff),(byte)((data >>> 8) & 0xff)};
}


public static long byteArrayToLong(byte[] b) {
    int  start = 0;
    int      i = 0;
    int    len = 4;
    int    cnt = 0;
    byte[] tmp = new byte[len];
    for (i = start; i < (start + len); i++) {
        tmp[cnt] = b[i];
        cnt++;
    }
    long accum = 0;
    i = 0;
    for (int shiftBy = 0; shiftBy < 32; shiftBy += 8) {
        accum |= ((long) (tmp[i] & 0xff)) << shiftBy;
        i++;
    }
    return accum;
}

}

文件mixed.wav,噪声范围视图的光谱分析 enter link description here

如果您遇到此问题,请给我一个解决方案。我该如何处理我的代码。你能帮我吗。我期待着您的建议。 非常感谢你。

1 个答案:

答案 0 :(得分:0)

您没有提供足够的代码以确定,但至少有一个问题:

在saveToFile函数中,您将样本解释为16位(myBitsPerSample),在混合代码中,您将样本解释为字节(可能是8位)。

其中一个是不正确的(我怀疑它是你的混合代码,但如果它们真的是8位文件,请记住wav文件不支持带符号的8位音频,所以你需要改变你的做法你的转换。)