using Android's AudioTrack to combine bytes of sound samples produces noise

放肆的年华 提交于 2019-11-30 15:40:20

I am not familiar with android audio, so I can't answer all your questions, but I can tell you what the fundamental problem is: adding audio data byte-by-byte won't work. Since it sort-of works, and from looking at your code, and the fact that it's most common, I'm going to assume you have 16-bit PCM data. Yet everywhere, you are dealing with bytes. Bytes are not appropriate for processing audio (unless the audio happens to be 8-bit)

Bytes are aprox +/- 128. You say "I would expect to see values ranging from −32768 to 32767 in logcat from the Log.d(...) invocation above, but instead the results tend to be within the range of -100 to 100 (with some outliers beyond that)" Well, how could you possibly go to that range when you are printing values from a byte array? The correct datatype for 16 bit signed data is short, not byte. If you were printing short values, you'd see the range you expected.

You must convert your bytes to shorts and sum the shorts. This will take care of much of the misc noise you are hearing. Since you are reading right off the file, though, why bother converting? why not read it off the file as a short using something like this http://docs.oracle.com/javase/1.4.2/docs/api/java/io/DataInputStream.html#readShort()

The next issue is that you must deal with out-of-range values, rather than letting them "wrap around". The simplest solution is simply to do the summing as integers, "clip" into the short range, and then store the clipped output. This will get rid of your clicks and pops.

In psuedo-code, the entire process will look something like this:

file1 = Open file 1
file2 = Open file 2
output = Open output for writing

numSampleFrames1 = file1.readHeader()
numSampleFrames2 = file2.readHeader()
numSampleFrames = min( numSampleFrames1, numSampleFrames2 )
output.createHeader( numSampleFrames )

for( int i=0; i<numSampleFrames * channels; ++i ) {
    //read data from file 1
    int a = file1.readShort();
    //read data from file 2, and add it to data we read from file 1
    a += file2.readShort();
    //clip into range
    if( a > Short.MAX_VALUE )
       a = Short.MAX_VALUE;
    if( a < Short.MIN_VALUE )
       a = Short.MIN_VALUE;
    //write it to the output
    output.writeShort( (Short) a );
}

You will get a little distortion from the "clipping" step, but there's no simple way around that, and clipping is MUCH better than wrap-around. (that said, unless your tracks are extremely "hot", and heavy in the low frequencies, the distortion shouldn't be too noticeable. If it is a problem, you can do other things: multiply a by .5 for example and skip the clipping, but then your output will be much quieter, which, on a phone, is probably not what you want).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!