如何使用javax.sound.sampled包同时播放一组频率(和弦)

我正在尝试实现一个系统,我可以一次播放一组频率,目前可以单独播放每个频率。 下面我有一个代码,它一次播放一个给定的频率。

import java.applet.*; import java.io.*; import java.net.*; import javax.sound.sampled.*; public final class StdAudio { public static final int SAMPLE_RATE = 44100; private static final int BYTES_PER_SAMPLE = 2; // 16-bit audio private static final int BITS_PER_SAMPLE = 16; // 16-bit audio private static final double MAX_16_BIT = Short.MAX_VALUE; // 32,767 private static final int SAMPLE_BUFFER_SIZE = 4096; private static SourceDataLine line; // to play the sound private static byte[] buffer; // our internal buffer private static int bufferSize = 0; // not-instantiable private StdAudio() { } // static initializer static { init(); } // open up an audio stream private static void init() { try { // 44,100 samples per second, 16-bit audio, mono, signed PCM, little Endian AudioFormat format = new AudioFormat((float) SAMPLE_RATE, BITS_PER_SAMPLE, 1, true, false); DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); line = (SourceDataLine) AudioSystem.getLine(info); line.open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE); buffer = new byte[SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE/3]; } catch (Exception e) { System.out.println(e.getMessage()); System.exit(1); } // no sound gets made before this call line.start(); } /** * Close standard audio. */ public static void close() { line.drain(); line.stop(); } /** * Write one sample (between -1.0 and +1.0) to standard audio. If the sample * is outside the range, it will be clipped. */ public static void play(double in) { // clip if outside [-1, +1] if (in  +1.0) in = +1.0; // convert to bytes short s = (short) (MAX_16_BIT * in); buffer[bufferSize++] = (byte) s; buffer[bufferSize++] = (byte) (s >> 8); // little Endian // send to sound card if buffer is full if (bufferSize >= buffer.length) { line.write(buffer, 0, buffer.length); bufferSize = 0; } } /** * Write an array of samples (between -1.0 and +1.0) to standard audio. If a sample * is outside the range, it will be clipped. */ public static void play(double[] input) { for (int i = 0; i < input.length; i++) { play(input[i]); } } private static double[] tone(double hz, double duration) { int N = (int) (StdAudio.SAMPLE_RATE * duration); double[] a = new double[N+1]; for (int i = 0; i <= N; i++) a[i] = amplitude * Math.sin(2 * Math.PI * i * hz / StdAudio.SAMPLE_RATE); return a; } /** * Test client - play an A major scale to standard audio. */ public static void main(String[] args) { double hz = 440.4// 440.4 Hz for 1 sec double duration = 1.0; double[] a = tone(hz,duration); StdAudio.play(a); } 

}

在此示例中 , Tone为每个Note打开一个SourceDataLine ,但您可以打开与和弦中的音符一样多的行。 然后简单地将和弦的每个Note write()到一个单独的行。 您可以使用Note.REST创建琶音效果。

只需对每个时间点的样本值求和,然后除以适当的比例因子,使值保持在范围内。 例如,要同时播放A 440和C 523.25:

 double[] a = tone(440,1.0); double[] b = tone(523.25,1.0); for( int i=0; i 

你可以为每个频率使用不同的线程:)

在这里你可以在java中找到一个小的线程示例

我希望这可以帮助你 :)