LoginSignup
0
0

More than 3 years have passed since last update.

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

Posted at

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

}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0