作为一个练习我正在尝试使用Thread.sleep作为计时器创建一个节拍器,使用JMF作为声音.它运作得很好,但由于某种原因,JMF似乎只播放每分钟最多207次的声音.
来自我的节拍器课程:
public void play() {
soundPlayer.play();
waitPulse();
play();
}
Run Code Online (Sandbox Code Playgroud)
从我的SoundPlayer类:
public void play() {
new Thread(new ThreadPlayer()).start();
}
private class ThreadPlayer implements Runnable {
public void run() {
System.out.println("Click");
player.setMediaTime(new Time(0));
player.start();
}
}
Run Code Online (Sandbox Code Playgroud)
我已经将SoundPlayer.play()作为一个线程来测试它是否会产生影响,但事实并非如此.我可以很容易地将速度改变到大约207bpm,但即使我将我的计时器设置为1000bpm,声音的播放速度也不会超过207bpm.
我把System.out.println("Click");我的ThreadPlayer.run()放在里面来检查我的循环是否正常工作 - 确实如此.
这个问题似乎与我对JMF的实施有关.我很确定有一个简单的解决方案,任何人都可以帮助我吗?
非常感谢你的帮助!:)
关于Thread.sleep()不可靠的答案是正确的:你不能指望它完全返回你指定的时间.事实上,我很惊讶你的节拍器可以使用,特别是当你的系统负载不足时.阅读Thread.sleep()的文档以获取更多详细信息.关于MIDI的Max Beikirch的答案是一个很好的建议:MIDI处理时机非常好.
但你问如何用音频做到这一点.诀窍是打开音频流并在节拍器点击之间填充静音,并将节拍器点击插入所需的位置.当您这样做时,您的声卡以恒定速率播放样本(无论它们是否包含咔嗒声或静音).这里的关键是保持音频流打开,永不关闭它.那么,时钟是音频硬件,而不是你的系统时钟 - 一个微妙但重要的区别.
因此,假设您正在以44100 Hz生成16位单声道样本.这是一个以所需速率创建咔嗒声的功能.请记住,这种咔嗒声对扬声器(和你的耳朵)来说是不好的,所以如果你真的使用它,请以低音量播放.(此外,此代码未经测试 - 只是为了演示这个概念)
int interval = 44100; // 1 beat per second, by default
int count = 0;
void setBPM( float bpm ) {
interval = ( bpm / 60 ) * 44100 ;
}
void generateMetronomeSamples( short[] s ) {
for( int i=0; i<s.length; ++i ) {
s = 0;
++count;
if( count == 0 ) {
s = Short.MAX_VALUE;
}
if( count == interval ) {
count = 0;
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用setBPM设置速度后,可以重复调用generateMetronomeSamples()函数生成的样本,并使用JavaSound将输出流式传输到扬声器.(请参阅JSResources.org以获得一个好的教程)
一旦你有了这个工作,你就可以用从WAV或AIFF或短音或其他任何东西获得的声音来代替刺耳的咔嗒声.
| 归档时间: |
|
| 查看次数: |
3618 次 |
| 最近记录: |