我正在尝试编写一个可用作节拍器的Android应用程序。这要求能够以准确的定时定期播放各种声音,但是现在我正在努力使声音开始工作。训练有素的听众可以轻松检测到超过2-3ms的错误。这是我的播放线程:
protected void onCreate(Bundle savedInstanceState) {
// stuff
int minBufferSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
}
public void startThread(View view){
mThread = new Thread (new Runnable() {
public void run(){
Log.d(TAG, "Starting met at tempo: " + mTempo + " Interval: " + (60000 / mTempo) );
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
InputStream in = getResources().openRawResource(R.raw.chirp);
byte [] output = getBytesFromStream(in);
Log.d(TAG, "Output length: " + output.length);
mAudioTrack.play();
while (mRunning) {
mAudioTrack.write(output, 0, output.length);
try {
Thread.sleep(60000 / mTempo);
} catch (InterruptedException e) {
}
}
mAudioTrack.release();
}
});
mThread.start();
}
R.raw.chirp是Audacity中产生的正弦波。 1000hz在44100hz处采样了100ms,因此应该是大约4410个样本。在Nexus 4上进行测试,将速度设置为200bpm(即,should声应每300ms播放一次),声音听起来不错,但我还是很好地通过线路输入将输出记录到了Audacity中。我注意到两个奇怪的地方:
1)chi声似乎在298-299毫秒之间的某段时间内播放。这在大多数情况下是一致的,但是1-2ms将速度更改为201bpm,这足以使它与引用节拍器不同步。
2)第二个奇数并非始终可重复,但是在看似随机的number声之后,单个chi声将延迟完整的20ms。
我可以想像地解释第二个问题。也许是线程/优先级问题?但是,第一个问题使我感到困惑。我想如果有什么鸣叫应该迟到,而不是早。我相信这些问题是相关的,而且我也开始认为我无法正确理解正在发生的事情,并且正在做一些非常基本的错误(这是我第一次使用任何类型的音频代码。)
任何帮助将非常感激。
最佳答案
除了目前使用不良的计时源外,还有一个更大的问题,即在请求播放的时间与实际发生的时间之间,Android仅提供相对宽松且实质上可变的耦合。
要解决此问题,请连续播放声音-大多数情况下保持静音-然后在所需时间混合所需的点击次数。无需使用任何普通的软件可访问系统时钟来确定时间,而应使用先前写入的样本的计数,这样您的时序将与数模转换器采样时钟具有固定的关系。
关于android - 在Android上准确播放定期声音,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17800776/