Javaでリサンプリングするだけ

PCマイクから8000Hz/16bitで取得し、線形補完による16000Hz/16bitにサンプリングする例です

``` java
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;
	}

}