I'm working on a project involved audio processing.
I'm taking a piece of audio from a file, and then would like to do some processing on it. The issue is that I get the audio data as byte array, while my processing is on double array (and later on Complex array as well...).
My question is that how can I correctly convert the byte array I receive to double array to go on?
Here's my input code:
AudioFormat format = new AudioFormat(8000, 16, 1, true, true);
AudioInputStream in = AudioSystem.getAudioInputStream(WAVfile);
AudioInputStream din = null;
AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
8000,
16,
1,
2,
8000,
true);
din = AudioSystem.getAudioInputStream(decodedFormat, in);
TargetDataLine fileLine = AudioSystem.getTargetDataLine(decodedFormat);
fileLine .open(format);
fileLine .start();
int numBytesRead;
byte[] targetData = new byte[256]; // (samplingRate / 1000) * 32ms
while (true) {
numBytesRead = din.read(targetData, 0, targetData.length);
if (numBytesRead == -1) {
break;
}
double[] convertedData;
// Conversion code goes here...
processAudio(convertedData);
}
So far I've looked into different answers to different question around this site and others. I've tried to use ByteBuffer and bit conversion, but both of them didn't give me results that seems right (another member in my them has done the same thing on the same file in Python so I have a reference what the results should approximately be...
What am I missing? How can I correctly convert the bytes to doubles? If I want to capture in targetData only 32ms of the file, what should be the length of targerData? What then will be the length of convertedData?
Thanks in advance.
The conversion using NIO buffers shouldn’t be so hard. All you have to do, is to apply a factor to normalize from a 16 Bit range, to a [-1.0…1.0]
range.
Well, it isn’t so easy, but for most practical purposes, deciding for one factor is sufficient:
AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
8000, 16, 1, 2, 8000, true);
try(AudioInputStream in = AudioSystem.getAudioInputStream(WAVfile);
AudioInputStream din = AudioSystem.getAudioInputStream(decodedFormat, in);
ReadableByteChannel inCh = Channels.newChannel(din)) {
ByteBuffer inBuf=ByteBuffer.allocate(256);
final double factor=2.0/(1<<16);
while(inCh.read(inBuf) != -1) {
inBuf.flip();
double[] convertedData=new double[inBuf.remaining()/2];
DoubleBuffer outBuf=DoubleBuffer.wrap(convertedData);
while(inBuf.remaining()>=2) {
outBuf.put(inBuf.getShort()*factor);
}
assert !outBuf.hasRemaining();
inBuf.compact();
processAudio(convertedData);
}
}
The solution above effectively uses the …/(double)0x8000
variant. Since I don’t know what processAudio
does with the supplied buffer, e.g. whether it keeps a reference to it, the loop allocates a new buffer in each iteration, but it should be easy to change it to a reusable buffer. You only have to take care about the actual number of read/converted doubles, when using a pre-allocated buffer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With