您如何创建一个音调发生器,其音调可以在 Java 中“实时”或动态操作?
Posted
技术标签:
【中文标题】您如何创建一个音调发生器,其音调可以在 Java 中“实时”或动态操作?【英文标题】:How do you create a tone generator whose tones can be manipulated "live" or on the fly in java? 【发布时间】:2012-04-27 21:07:15 【问题描述】:我想用java制作一个基本的音调发生器,可以实时操作(只是音高开始)。
我想从简单开始,然后添加更复杂的音调生成和效果,最终得到某种基本的合成器。
我发现 a helpful post on this site 在一个小程序 Beeper.java 中有一些示例代码。
它会生成一个音调并将其保存到一个剪辑中。然后,它会在需要时循环播放该剪辑。相关音调产生位:
/** Generates a tone, and assigns it to the Clip. */
public void generateTone()
throws LineUnavailableException
if ( clip!=null )
clip.stop();
clip.close();
else
clip = Audiosystem.getClip();
boolean addHarmonic = harmonic.isSelected();
int intSR = ((Integer)sampleRate.getSelectedItem()).intValue();
int intFPW = framesPerWavelength.getValue();
float sampleRate = (float)intSR;
// oddly, the sound does not loop well for less than
// around 5 or so, wavelengths
int wavelengths = 20;
byte[] buf = new byte[2*intFPW*wavelengths];
AudioFormat af = new AudioFormat(
sampleRate,
8, // sample size in bits
2, // channels
true, // signed
false // bigendian
);
int maxVol = 127;
for(int i=0; i<intFPW*wavelengths; i++)
double angle = ((float)(i*2)/((float)intFPW))*(Math.PI);
buf[i*2]=getByteValue(angle);
if(addHarmonic)
buf[(i*2)+1]=getByteValue(2*angle);
else
buf[(i*2)+1] = buf[i*2];
try
byte[] b = buf;
AudioInputStream ais = new AudioInputStream(
new ByteArrayInputStream(b),
af,
buf.length/2 );
clip.open( ais );
catch(Exception e)
e.printStackTrace();
循环位:
/** Loops the current Clip until a commence false is passed. */
public void loopSound(boolean commence)
if ( commence )
clip.setFramePosition(0);
clip.loop( Clip.LOOP_CONTINUOUSLY );
else
clip.stop();
我试图解决这个问题,以便在背景中创建另一个剪辑,并在我想更改音高时快速更改另一个剪辑,但是当一个剪辑开始而另一个剪辑停止时,当然会有明显的咔哒声。
所以我猜我需要某种巧妙的缓冲来做到这一点,将一个波的结束与另一波无缝匹配?
或者只是不能使用预先生成的剪辑?如果是这样,我应该怎么做?
顺便说一句,软件合成器是如何工作的?它们是连续生成所有声音和效果,还是像 Beeper.java 一样预生成“剪辑”和循环?
谢谢!
【问题讨论】:
【参考方案1】:听起来你想用 Java 实现一个numerically controlled oscillator (NCO),用相位累加器实现。
基本上,您需要计算出所需频率的增量相位,然后继续将其以 2pi 为模数添加到累加器中。将累加器的值作为sin()
的值,生成样本值。
当您想要更改频率时,您需要更新 delta-phase。这确保了样本的连续性(波中没有突然中断)。我怀疑这是导致您点击的原因。如果你想要更好的改变,那么你需要在一堆样本上逐渐改变 delta-phase。
【讨论】:
谢谢,我想我明白你在说什么,但这一切真的有点超出我的想象。这是我应该使用剪辑做的事情,还是我应该不断地产生音调并立即播放? 我认为如果你不想有不连续性,剪辑可能会很棘手。任意频率不会有恰好对应于一个波周期的“好”数量的样本。 是的,我是这么认为的......你不能给我指出一些使用标准 api 的基本 Java 代码,这些代码可以说明正弦波的“实时”生成和回放,可以吗?! :) 好吧,我找到了一些 java 示例,并尝试使用代码,但我意识到我只是不了解我正在尝试做的事情的基础知识!如果您知道有关此主题的任何基本教程(即不适用于数学专业),那将非常有帮助!以上是关于您如何创建一个音调发生器,其音调可以在 Java 中“实时”或动态操作?的主要内容,如果未能解决你的问题,请参考以下文章