我有以下类生成包含声音数据的缓冲区:
package musicbox.example;
import javax.sound.sampled.LineUnavailableException;
import musicbox.engine.SoundPlayer;
public class CChordTest {
private static final int SAMPLE_RATE = 1024 * 64;
private static final double PI2 = 2 * Math.PI;
/*
* Note frequencies in Hz.
*/
private static final double C4 = 261.626;
private static final double E4 = 329.628;
private static final double G4 = 391.995;
/**
* Returns buffer containing audio information representing the C chord
* played for the specified duration.
*
* @param duration The duration in milliseconds.
* @return Array of bytes representing the audio information.
*/
private static byte[] generateSoundBuffer(int duration) {
double durationInSeconds = duration / 1000.0;
int samples = (int) durationInSeconds * SAMPLE_RATE;
byte[] out = new byte[samples];
for (int i = 0; i < samples; i++) {
double value = 0.0;
double t = (i * durationInSeconds) / samples;
value += Math.sin(t * C4 * PI2); // C note
value += Math.sin(t * E4 * PI2); // E note
value += Math.sin(t * G4 * PI2); // G note
out[i] = (byte) (value * Byte.MAX_VALUE);
}
return out;
}
public static void main(String... args) throws LineUnavailableException {
SoundPlayer player = new SoundPlayer(SAMPLE_RATE);
player.play(generateSoundBuffer(1000));
}
}
也许我在这里误解了一些物理或数学,但似乎每个正弦曲线应该代表每个音符(C,E和G)的声音,并且通过对三个正弦曲线求和,我应该听到一些东西类似于我在键盘上同时播放这三个音符时的情况。然而,我听到的内容甚至不是那么接近。
对于它的价值,如果我注释掉任何两个正弦曲线并保留第三个正弦曲线,我确实会听到对应于该正弦波的(正确)音符。
有人可以发现我做错了吗?
答案 0 :(得分:1)
要合并音频信号,您需要对其样本进行平均,而不是将它们相加。
在转换为byte之前将值除以3。
答案 1 :(得分:1)
您没有说听起来有什么不对劲,而是添加三个正弦值,例如,您将获得一个范围从-3.0到3.0的信号,因此当您应用* Byte.MAX_VALUE时将被裁剪,这就是为什么平均可能为您工作的原因,添加正确的位子只是您需要缩放结果以防止削波和除以正弦波数,这是最简单的方法。但是,如果您开始动态地改变正弦波的数量,并尝试使用相同的策略,那么您将无法获得预期的结果,则必须在信号最大时缩放信号。请记住,真实音频不会达到最大幅度,因此,如果合成音频不是,则不必担心两个,而且,我们感知音量的方式是对数的,因此半幅度的信号会有所不同的-3dB,非常接近我们听到的最小幅度变化。