gpt4 book ai didi

java - Java 上的多种声音

转载 作者:搜寻专家 更新时间:2023-11-01 02:15:02 26 4
gpt4 key购买 nike

我想在 Java 中同时播放 2 种声音(例如 220Hz 和 440Hz)。

我设法使用 StdAudio 播放了一种声音.后来我把它改成了非静态的,去掉了一些与我无关的方法。

我不知道的是如何同时播放 2 个声音。我尝试用线程来做到这一点,但它们并不总是同步的。

下面是我修改后的 StdAudio 版本,下面是我如何尝试使用线程的示例。

程序.java

public class program {

public static void main(String[] args) {
Thread t1 = new Thread(new soundThread(220));
t1.start();
Thread t2 = new Thread(new soundThread(440));
t2.start();

t1.notify();
t2.notify();
}

}

声音线程.java

public class soundThread implements Runnable {
private int fq;

public soundThread(int fq) {
this.fq = fq;
}

public void run() {
StdAudio s = new StdAudio();
double[] note = s.note(fq, 2, 1);
try {
this.wait();
} catch (Exception e) {
}

s.play(note);

s.close();
}

}

标准音频.java

/*************************************************************************
* Compilation: javac this.java
* Execution: java StdAudio
*
* Simple library for reading, writing, and manipulating .wav files.

*
* Limitations
* -----------
* - Does not seem to work properly when reading .wav files from a .jar file.
* - Assumes the audio is monaural, with sampling rate of 44,100.
*
*************************************************************************/

import javax.sound.sampled.*;

/**
* <i>Standard audio</i>. This class provides a basic capability for creating,
* reading, and saving audio.
* <p>
* The audio format uses a sampling rate of 44,100 (CD quality audio), 16-bit,
* monaural.
*
* <p>
* For additional documentation, see <a
* href="http://introcs.cs.princeton.edu/15inout">Section 1.5</a> of
* <i>Introduction to Programming in Java: An Interdisciplinary Approach</i> by
* Robert Sedgewick and Kevin Wayne.
*/
public final class StdAudio {

/**
* The sample rate - 44,100 Hz for CD quality audio.
*/
public final int SAMPLE_RATE = 44100;

private final int BYTES_PER_SAMPLE = 2; // 16-bit audio
private final int BITS_PER_SAMPLE = 16; // 16-bit audio
private final double MAX_16_BIT = Short.MAX_VALUE; // 32,767
private final int SAMPLE_BUFFER_SIZE = 4096;

private SourceDataLine line; // to play the sound
private byte[] buffer; // our internal buffer
private int bufferSize = 0; // number of samples currently in internal
// buffer

// initializer
{
init();
}

// open up an audio stream
private 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);

// the internal buffer is a fraction of the actual buffer size, this
// choice is arbitrary
// it gets divided because we can't expect the buffered data to line
// up exactly with when
// the sound card decides to push out its samples.
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 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 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 void play(double[] input) {
for (int i = 0; i < input.length; i++) {
play(input[i]);
}
}

/**
* Create a note (sine wave) of the given frequency (Hz), for the given
* duration (seconds) scaled to the given volume (amplitude).
*/
public double[] note(double hz, double duration, double amplitude) {
int N = (int) (this.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 / this.SAMPLE_RATE);
return a;
}

}

提前致谢,谢本摩西

编辑:解决方案是编写此方法:

public double[] multipleNotes(double[] hzs, double duration,
double amplitude) {
amplitude = amplitude / hzs.length;
int N = (int) (SAMPLE_RATE * duration);
double[] a = new double[N + 1];
for (int i = 0; i <= N; i++) {
a[i] = 0;
for (int j = 0; j < hzs.length; j++)
a[i] += amplitude
* Math.sin(2 * Math.PI * i * hzs[j] / SAMPLE_RATE);
}
return a;
}

编辑 2:对我来说更好的解决方案(O(1) 内存):

public void multiplePlay(double[] hzs, double duration, double amplitude) {
amplitude = amplitude / hzs.length;
int N = (int) (SAMPLE_RATE * duration);
double sum;
for (int i = 0; i <= N; i++) {
sum = 0;
for (int j = 0; j < hzs.length; j++)
sum += amplitude
* Math.sin(2 * Math.PI * i * hzs[j] / SAMPLE_RATE);
this.play(sum);
}
}

最佳答案

扩展一下我关于简单地将两种声音合二为一的评论......

你展示了这个:

public double[] note(double hz, double duration, double amplitude) {
int N = (int) (this.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 / this.SAMPLE_RATE);
return a;
}

那么,将两种声音混合成一种并播放一种独特的声音怎么样?例如你可以这样做:

public double[] notes(double hz1, double hz2, double duration, double amplitude) {
final double[] a1 = note( hz1, duration, amplitude );
final double[] a2 = note( hz2, duration, amplitude );
final double[] a3 = new double[a2.length];
for ( int i = 0; i < a1.length; i++ ) {
a3[i] = (a1[i] + a2[i]) / 2;
}
return a3;
}

你可以这样调用它:

final double[] sound = notes(220,400,...,...);

关于java - Java 上的多种声音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7875861/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com