在Java中,有没有办法合成特定频率的音调?

时间:2012-05-23 23:52:13

标签: java javasound sound-synthesis

我正在与binaural beats做一些工作,我正在尝试构建一个Java应用程序,可以在略微不同的频率播放两个声音...大约25-30Hz的差异。

在一个完美的世界里,我想给Java两个整数输入,比如440和410,并让Java播放440Hz音调和410Hz音调。

鉴于我在javax.sound.*课程中看到的内容,似乎Java只支持相当于钢琴音符... A4 @ 440Hz,然后是A-sharp-4 @ 466.164Hz,而在另一个方向,G-sharp-4 @ 415.305Hz。虽然“相邻”通常在产生双耳节拍的范围内,但我试图在音调的频率上实现更多的控制。

由于简单的音频合成只不过是频率,强度和时间长度,所以出现对我来说javax.sound.*类的某些地方,有某种查询说当我告诉Java播放“A4”时,那是440Hz。问题在于是否有办法破解该表,说“A4.1”相当于449Hz。

我一直在搞javax.sound.midi,还没有探讨过javax.sound.sampled;似乎我需要对我的音调进行采样以使用sampled类;我更喜欢合成。如果我错了,请引导我。

我见过的大多数第三方界面都专门针对音乐制作和操作,因此,他们使用微调的能力有限。有没有人对解决方案有任何经验或建议?

2 个答案:

答案 0 :(得分:5)

您可以使用javax.sound.sampled.*中的类生成样本并将其发送到声卡;基本上创建一个软件振荡器。

它需要一些知识,但是当你开始工作时会非常有趣;)

当我创建这个时,我正在玩这些类:http://bobusumisu.net/testing/bobusynth-alpha1/

这是让我入门的教程:http://www.drdobbs.com/jvm/230500178

答案 1 :(得分:4)

这只是为了补充已经提供和接受的答案(我给了+1)。

您可以使用波表作为动态运行trig函数的替代方法 - 一半采样/半合成。我还使用带有六个独立光标的正弦波表进行FM合成,并以这种方式复制了几个Yamaha DX7贴片。但这都是通过javax.sound.sampled完成的。一旦构建了软合成器,您可能希望使用midi库类来控制它。

假设您使用浮点数填充1K数组以获得单个正弦波。

如果通过递增并循环遍历波形表并依次提取每个阵列成员(通过SourceDataLine写入声卡)来“播放”波表,您将获得与采样率直接相关的音高。对于每秒44100个样本,1024个成员的阵列将循环44100/1024 = 43.066 ...次以用数据填充“秒”(非常低的音高 - 大约43Hz)。如果你跳过每个第二个表成员,则音高是两倍,等等。要获得音高440,需要找到用于逐步通过波表数组的正确“增量”,可以找到: incr =(waveTable *所需音高的大小)/采样率

例如 (1024 * 440)/ 44100给出一个增量:10.21678 ...... 因此,如果waveTable的第一个值位于数组位置0,则要使用的第二个值将位于位置10和11之间。要获得位于两个数组位置之间的值,请使用线性插值。

我使用此方法,使用javax.sound.sampled库,在此链接上使用“Theremin”。显示键盘,但在键盘上移动鼠标时,您可以轻松听到/看到微调控制。

http://www.hexara.com/VSL/JTheremin.htm

在上面,鼠标位置(通过MouseMotionListener调用)用于通过此函数计算所需的音高:

return Math.pow(2, ((mouseX + tuningLoc) / (octaveWidth)));

其中octaveWidth是覆盖八度音程的像素数。