1

とりわけメトロノームとして機能する 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番目の問題は、おそらく説明できませんでした。おそらくスレッド/優先度の問題ですか?しかし、最初の問題は私を困惑させます。どちらかといえば、チャープは早くではなく遅く来るはずだと思います。私はこれらの問題が関連していると信じており、何が起こっているのかを正しく理解しておらず、非常に基本的な間違ったことをしていると考え始めています (オーディオコードを扱うのはこれが初めてです)。

どんな助けでも大歓迎です。

4

2 に答える 2

5

現在、不十分なタイミング ソースを使用していることに加えて、Android では、再生が要求された時間と実際に発生した時間との間の結合が比較的緩く、実質的に変動するだけであるという、より大きな問題があります。

これを回避するには、サウンドを連続的に再生し (ほとんど無音で)、目的のタイミングで目的のクリックをミックスします。通常のソフトウェア アクセス可能なシステム クロックを使用して時間を決定する代わりに、以前に書き込まれたサンプルのカウントを使用して、タイミングがデジタル アナログ コンバーターのサンプリング クロックと一定の関係になるようにします。

于 2013-07-23T04:10:24.057 に答える
0

したがって、睡眠が正確であることに依存しています。そうではありません。なるように設計されていません。少なくともその時間はスリープしますが、それ以上スリープする可能性があります。OS は、スリープ状態になるとすぐにそのスレッドにタスク スイッチを戻すのではなく、そのスレッドがスケジューリング キューで最優先のスレッドになるとすぐに切り替えます。RTC に基づく、はるかに信頼性の高い待機方法が必要です。

RTC アラーム タイプに基づくアラームがそれを行う可能性があります。それが実際に即時アラームを送信するRTC割り込みなのか、それともそれが使用する相対クロックなのかはわかりません。

于 2013-07-23T03:09:40.173 に答える