Java生成声音

15

我创建了一个乒乓球克隆游戏,并希望在碰撞发生时添加一些音效。我的问题是,我找到的所有有关合成声音的例子都需要大约30行代码,考虑到我的整个应用程序只有90行代码。我正在寻找一种更简单的方法。是否有一种简单的方法可以创建不同音调的蜂鸣声?持续时间不重要。我只想要一系列具有不同音调的蜂鸣声。


2
30行代码并不多。使用你找到的示例有什么问题吗? - Joe
1
是的,我知道,但整个克隆代码有90行。其中三分之一的代码将仅用于创建一个简单的蜂鸣声。对我来说有点无意义,但如果我找不到其他方法,我会选择这种方式。 - Hamza Yerlikaya
7
事后看来,四分之一的代码存在问题。如果这样说能让你感觉好些的话... - Sev
4个回答

24

以下是从Java声音 - 示例:生成音频音调的代码中提取并简化的小例子:

    byte[] buf = new byte[ 1 ];;
    AudioFormat af = new AudioFormat( (float )44100, 8, 1, true, false );
    SourceDataLine sdl = AudioSystem.getSourceDataLine( af );
    sdl.open();
    sdl.start();
    for( int i = 0; i < 1000 * (float )44100 / 1000; i++ ) {
        double angle = i / ( (float )44100 / 440 ) * 2.0 * Math.PI;
        buf[ 0 ] = (byte )( Math.sin( angle ) * 100 );
        sdl.write( buf, 0, 1 );
    }
    sdl.drain();
    sdl.stop();

2
你能解释一下为什么在这行代码中要乘以100而不是128吗? buf[ 0 ] = (byte )( Math.sin( angle ) * 100 );我觉得很困惑,因为我本来以为信号应该在-127到127之间。另外,链接已经失效了,请尽可能更新。 - Felix
这只会影响声音的振幅(即音量)。 - while
2
“i < 1000 * (float)44100 / 1000”的意义在哪里?难道和“i < (float)44100”不是一样的吗? - dk14
1
@dk14,前1000个将允许您更改示例的长度,我假设是毫秒。 - Firedan1176

9

这里是与上面代码相同的16位描述:

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

public class MakeSound {
  public static void main(String[] args) throws LineUnavailableException {
    System.out.println("Make sound");
    byte[] buf = new byte[2];
    int frequency = 44100; //44100 sample points per 1 second
    AudioFormat af = new AudioFormat((float) frequency, 16, 1, true, false);
    SourceDataLine sdl = AudioSystem.getSourceDataLine(af);
    sdl.open();
    sdl.start();
    int durationMs = 5000;
    int numberOfTimesFullSinFuncPerSec = 441; //number of times in 1sec sin function repeats
    for (int i = 0; i < durationMs * (float) 44100 / 1000; i++) { //1000 ms in 1 second
      float numberOfSamplesToRepresentFullSin= (float) frequency / numberOfTimesFullSinFuncPerSec;
      double angle = i / (numberOfSamplesToRepresentFullSin/ 2.0) * Math.PI;  // /divide with 2 since sin goes 0PI to 2PI
      short a = (short) (Math.sin(angle) * 32767);  //32767 - max value for sample to take (-32767 to 32767)
      buf[0] = (byte) (a & 0xFF); //write 8bits ________WWWWWWWW out of 16
      buf[1] = (byte) (a >> 8); //write 8bits WWWWWWWW________ out of 16
      sdl.write(buf, 0, 2);
    }
    sdl.drain();
    sdl.stop();
  }
}

7

您可以使用JSyn。这是一个库,您需要安装它(包括一个.DLL和一个.JAR文件)。但非常容易创建不同的音调。

链接(还提供教程)

这是一个示例:

public static void main(String[] args) throws Exception {
    SawtoothOscillatorBL osc;
    LineOut lineOut;
    // Start JSyn synthesizer.
    Synth.startEngine(0);

    // Create some unit generators.
    osc = new SawtoothOscillatorBL();
    lineOut = new LineOut();

    // Connect oscillator to both left and right channels of output.
    osc.output.connect(0, lineOut.input, 0);
    osc.output.connect(0, lineOut.input, 1);

    // Start the unit generators so they make sound.
    osc.start();
    lineOut.start();

    // Set the frequency of the oscillator to 200 Hz.
    osc.frequency.set(200.0);
    osc.amplitude.set(0.8);

    // Sleep for awhile so we can hear the sound.
    Synth.sleepForTicks(400);

    // Change the frequency of the oscillator.
    osc.frequency.set(300.0);
    Synth.sleepForTicks(400);

    // Stop units and delete them to reclaim their resources.
    osc.stop();
    lineOut.stop();
    osc.delete();
    lineOut.delete();

    // Stop JSyn synthesizer.
    Synth.stopEngine();
}

Martijn

1
JSyn现在是纯Java,不再需要本地DLL。 - philburk
1
Android:JSyn现在可以在2023年使用,我可以确认。只需要下载AndroidAudioForJSyn类,而不仅仅是jar文件。 - djdance

6

java.awt.Toolkit.getDefaultToolkit().beep()

这段代码会发出一系列的蜂鸣声。

int numbeeps = 10;

for(int x=0;x<numbeeps;x++)
{
  java.awt.Toolkit.getDefaultToolkit().beep();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接