4. Redefining the problem
• Let’s make it a simpler problem, by taking away the part
that we can figure out ourselves
• We can split the incoming stream into sound samples of
some length (moving window)
• So let’s try to find a way to compare two sound samples
10. Reading PCM data
byte[] rawBuffer = new byte[4096];
final int SAMPLE_SIZE = 4; // 2 bytes * 2 channels
ByteBuffer sample = ByteBuffer.allocate(SAMPLE_SIZE);
sample.order(ByteOrder.LITTLE_ENDIAN);
while (true) {
int length = input.read(rawBuffer);
// consume the rawBuffer
for (int i = 0; i < length; i += SAMPLE_SIZE) {
sample.clear();
sample.put(rawBuffer, i, SAMPLE_SIZE);
sample.rewind();
while (sample.hasRemaining()) {
short left = sample.getShort();
short right = sample.getShort();
// ...
}
}
}
13. Porting xcorr from Octave
N = max(length(X),length(Y));
maxlag = N - 1;
M = 2^nextpow2(N + maxlag);
pre = fft( postpad( prepad( X(:), length(X)+maxlag ), M) );
post = fft( postpad( Y(:), M ) );
cor = ifft( pre .* conj(post) );
R = cor(1:2*maxlag+1);
R = real(R);
public class Waveform {
private final float[] buffer;
private final int length;
// ...
}
Waveform x = currentWindow;
Waveform y = jingle
.setPadding(jingle.getSize() + windowSize - 1, next2Pow)
.doFft();
x.doFft();
x.doConjAndMultiply(y);
x.doIfft();
float[] result = y.getMaxReal(2 * windowSize + 1);
14. FFT usage in Java
// https://github.com/wendykierp/JTransforms
import org.jtransforms.fft.FloatFFT_1D;
short[] shortBuffer; // (-32678,32767)
float[] buffer = shortBuffer / 32768;
// fft()
FloatFFT_1D fft = new FloatFFT_1D(length);
fft.realForwardFull(buffer);
// ifft()
fft.complexInverse(buffer, true);
buffer[i]; // i%2 == 0; real part
buffer[i+1]; // imaginary part