1

デジタル オーディオ (合成音楽) と MIDI 音楽 (RtMidi ライブラリを使用) の両方を同時に再生する C++ コードを書いています。デジタル化された音楽はコンピューターのオーディオ デバイスから再生されますが、MIDI 音楽は外部シンセサイザー。デジタル化された楽器と MIDI 楽器の両方を使用する曲を再生したいのですが、これら 2 つのオーディオ ストリームを同期させる最善の方法がわかりません。

  • Sleep() のような関数を使用することはできません。遅延時間が不均一であり、私のニーズ (1 ミリ秒のオーダー) に対して長すぎるためです。結果として得られる曲のテンポはオフになり、呼び出されるたびに正確でない限り、テンポは不均一になります。
  • オーディオ バッファに配置されたサンプル数をカウントすると、デジタル オーディオのノート間の非常に正確なタイミングが得られます (1 サンプルの最小遅延 - 48kHz で 0.02ms) が、このタイミングは MIDI には使用できません。オーディオはバッファリングされるため、ノートはバーストで合成されます (一度に 1 つのオーディオ バッファをできるだけ早く埋めます)。その結果、デジタル オーディオ バッファが必要になるたびに、一連の MIDI ノートが遅延なく再生されます。補充されます。
  • ライブ MIDI データの再生にはタイミング情報がないため、ノートは送信されるとすぐに再生されます。したがって、ノートを後で再生するようにスケジュールすることはできません。そのため、正確な時間に正確に MIDI イベントを自分で送信する必要があります。

現在、私は nanosleep() を使用しています - これは Windows ではなく Linux でのみ動作します - ノート間の正しい時間を待つために。これにより、デジタル オーディオと MIDI データの両方の同期を維持できますが、nanosleep() はあまり一貫性がないため、結果のテンポは非常に不均一になります。

デジタル オーディオと MIDI データの両方で、ノート間の正確なタイミングを維持する方法を考えられる人はいますか?

4

3 に答える 3

2

Boost を使用する場合は、CPU 精度のタイマーがあります。そうでない場合、Windows には、CPU ベースのタイミングに使用できる関数QueryPerformanceCounterとがありQueryPerformanceFrequency、すべてのニーズに確実に適合します。Web には多くの Timer クラスの実装があり、そのうちのいくつかは Windows と *ix システムの両方で動作します。

于 2012-06-10T14:30:40.093 に答える
1

最初の問題は、オーディオ デバイスを通過したオーディオの量を知る必要があることです。レイテンシーが十分に低い場合は、プッシュしたデータの量から推測することができるかもしれませんが、それと再生の間のレイテンシーは移動するターゲットであるため、オーディオからその情報を取得するようにしてください。ハードウェア。レイテンシー測定のエラーから得られる「ジッター」は、音楽的に目立つ方法で同期に影響を与える可能性があるため、この情報を使用してください。

タイミングのためにスリープを使用する必要がある場合、スリープを長くする 2 つの問題があります。システムがプロセス/スレッドを交換するのに 5 ミリ秒かかるため、要求された遅延時間にそれが追加される可能性があります)。この種の遅延は、音楽的に関連しています。ほとんどの midi API には「シーケンサ」API があり、システム タイマーを使用しなくても済むように、事前にデータをキューに入れることができます。

オーディオ I/O に portaudio を使用していない場合でも、このドキュメントが役立つ場合があります。

http://www.portaudio.com/docs/portaudio_sync_acmc2003.pdf

于 2012-06-11T14:51:21.707 に答える
0

これに対する答えは、小さなバッファーではなく、大きなバッファーにあります。

3分間の曲を例に挙げてみましょう。

最初にデジタル部分をレンダリングし、MIDI ノートで「タグ付け」します。次に、再生を開始し、時間になったら MIDI ノートをトリガーします。おそらく std::vector を使用して順序リストを保持します。同期は、全体の時間オフセットを使用して変更できます。

恐ろしい不完全ですが、うまくいけばこのトピックに関するデモ用の疑似コード:

start_digital_playing_thread();
int midi_time_sync = 10; // ms
if (time >= (midi_note[50]->time + midi_time_sync)) // play note
于 2012-06-10T14:42:23.607 に答える