PCマイクから8000Hz/16bitで取得し、線形補完による16000Hz/16bitにサンプリングする例です
import static java.lang.System.out;
import java.util.Arrays;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;
import javax.sound.sampled.DataLine.Info;
public class MicrophoneResamplingTest {
// SampleRate:8000Hz, SampleSizeInBits: 16, Number of channels: 1, Signed:true, bigEndian: false
public static final AudioFormat audioFormat = new AudioFormat(8000, 16, 1, true, false);
// Set the system information to read from the microphone audio stream
public static final DataLine.Info targetInfo = new Info(TargetDataLine.class, audioFormat);
public static void main(String[] args) throws Exception {
if (!AudioSystem.isLineSupported(targetInfo)) {
out.println("Microphone not supported");
return;
}
new MicrophoneResamplingTest().test();
}
// マイク音声を取得しリサンプリング
void test() throws Exception {
TargetDataLine dataLine = (TargetDataLine) AudioSystem.getLine(targetInfo);
dataLine.open(audioFormat);
dataLine.start();
byte[] bytes = new byte[1024];
while (dataLine.isOpen()) {
int numBytesRead = dataLine.read(bytes, 0, bytes.length);
if ((numBytesRead <= 0) && (dataLine.isOpen()))
continue;
// 例:8000Hzから16000Hzのupsampling
byte[] resampled = resampling(bytes, 16, 8000, 16000);
out.println(Arrays.toString(resampled));// リサンプリングされたデータ
}
}
// 線形補間によるリサンプリング
byte[] resampling(byte[] sourceData, int bitsPerSample, int sourceRate, int targetRate) {
int bytePerSample = bitsPerSample / 8;
int numSamples = sourceData.length / bytePerSample;
short[] amplitudes = new short[numSamples];
int pointer = 0;
for (int i = 0; i < numSamples; i++) {
short amplitude = 0;
for (int byteNumber = 0; byteNumber < bytePerSample; byteNumber++)
amplitude |= (short) ((sourceData[pointer++] & 0xFF) << (byteNumber * 8));
amplitudes[i] = amplitude;
}
// Linear interpolation
short[] targetSample = interpolate(sourceRate, targetRate, amplitudes);
int targetLength = targetSample.length;
byte[] bytes;
if (bytePerSample == 1) {
bytes = new byte[targetLength];
for (int i = 0; i < targetLength; i++)
bytes[i] = (byte) targetSample[i];
} else {
bytes = new byte[targetLength * 2];
for (int i = 0; i < targetSample.length; i++) {
bytes[i * 2] = (byte) (targetSample[i] & 0xff);
bytes[i * 2 + 1] = (byte) ((targetSample[i] >> 8) & 0xff);
}
}
return bytes;
}
// 線形補間
short[] interpolate(int oldSampleRate, int newSampleRate, short[] samples) {
if (oldSampleRate == newSampleRate)
return samples;
int newLength = Math.round(((float) samples.length / oldSampleRate * newSampleRate));
float lengthMultiplier = (float) newLength / samples.length;
short[] interpolatedSamples = new short[newLength];
for (int i = 0; i < newLength; i++) {
float currentPosition = i / lengthMultiplier;
int nearestLeftPosition = (int) currentPosition;
int nearestRightPosition = nearestLeftPosition + 1;
if (nearestRightPosition >= samples.length)
nearestRightPosition = samples.length - 1;
float slope = samples[nearestRightPosition] - samples[nearestLeftPosition];
float positionFromLeft = currentPosition - nearestLeftPosition;
interpolatedSamples[i] = (short) (slope * positionFromLeft + samples[nearestLeftPosition]);
}
return interpolatedSamples;
}
}