裸金属声

使用 java 生成声音时,你也可以使用几乎裸机。此代码将原始二进制数据写入 OS 音频缓冲区以生成声音。理解产生这样的声音的局限性和必要的计算是非常重要的。由于回放基本上是瞬时的,因此需要几乎实时地进行计算。

因此,该方法不能用于更复杂的声音采样。出于此目的,使用专用工具是更好的方法。

以下方法在给定的持续时间内生成并直接输出给定体积中给定频率的矩形波。

public void rectangleWave(byte volume, int hertz, int msecs) {
    final SourceDataLine dataLine;
    // 24 kHz x 8bit, single-channel, signed little endian AudioFormat
    AudioFormat af = new AudioFormat(24_000, 8, 1, true, false);
    try {
        dataLine = AudioSystem.getSourceDataLine(af);
        dataLine.open(af, 10_000); // audio buffer size: 10k samples
    } catch (LineUnavailableException e) {
        throw new RuntimeException(e);
    }

    int waveHalf = 24_000 / hertz; // samples for half a period
    byte[] buffer = new byte[waveHalf * 20];
    int samples = msecs * (24_000 / 1000); // 24k (samples / sec) / 1000 (ms/sec) * time(ms)

    dataLine.start(); // starts playback
    int sign = 1;

    for (int i = 0; i < samples; i += buffer.length) {
        for (int j = 0; j < 20; j++) { // generate 10 waves into buffer
            sign *= -1; 
            // fill from the jth wave-half to the j+1th wave-half with volume
            Arrays.fill(buffer, waveHalf * j, waveHalf * (j+1), (byte) (volume * sign));
        }
        dataLine.write(buffer, 0, buffer.length); // 
    }
    dataLine.drain(); // forces buffer drain to hardware
    dataLine.stop();  // ends playback
}

对于产生不同声波的更加差异化的方式,需要进行窦计算和可能更大的样本大小。这导致明显更复杂的代码,因此在此省略。