1

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

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

}

}

4

3 回答 3

3

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

double[] a = tone(440,1.0);
double[] b = tone(523.25,1.0);
for( int i=0; i<a.length; ++ i )
   a[i] = ( a[i] + b[i] ) / 2;
StdAudio.play(a);
于 2012-08-09T22:56:36.217 回答
1

在此示例中,为每个Tone打开一个单曲,但您可以打开与和弦中的音符一样多的行。然后简单地把每个和弦换成单独的一行。您可以使用 来创建琶音效果。SourceDataLineNotewrite()NoteNote.REST

于 2012-08-09T10:54:49.770 回答
0

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

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

我希望这可以帮助你 :)

于 2012-08-09T10:56:45.470 回答