とりわけメトロノームとして機能する Android アプリを作成しようとしています。これには、さまざまな音を定期的に正確なタイミングで再生する機能が必要ですが、今のところ、1 つだけを動作させることに取り組んでいます。2 ~ 3 ミリ秒を超えるエラーは、訓練を受けたリスナーによって簡単に検出されます。ここに私の再生スレッドがあります:
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 に設定して (つまり、チャープは 300 ミリ秒ごとに再生する必要があります)、サウンドは良好に見えましたが、適切な測定のために、ライン入力を介して出力を Audacity に録音しました。私は2つの奇妙な点に気付きました:
1) チャープは、298 ~ 299 ミリ秒の間のどこかの期間で再生されているように見えました。これはほとんど一貫していましたが、その 1 ~ 2 ミリ秒でテンポが 201bpm に変更されました。
2) 2 番目の奇妙さは一貫して再現可能ではありませんでしたが、一見ランダムな数のチャープの後に、完全に 20 ミリ秒遅れて単一のチャープが発生しました。
2番目の問題は、おそらく説明できませんでした。おそらくスレッド/優先度の問題ですか?しかし、最初の問題は私を困惑させます。どちらかといえば、チャープは早くではなく遅く来るはずだと思います。私はこれらの問題が関連していると信じており、何が起こっているのかを正しく理解しておらず、非常に基本的な間違ったことをしていると考え始めています (オーディオコードを扱うのはこれが初めてです)。
どんな助けでも大歓迎です。