SharpDX サンプル ( https://github.com/sharpdx/SharpDX-Samples/blob/master/WindowsDesktop/XAudio2/AudioPlayerApp/AudioPlayer.cs ) のストリーミングの原則を使用して、同時に複数のサウンドを再生しています。
同じ曲の複数のバージョンを含むリストがあります。私はそれらをまったく同時に開始したい。曲ごとに新しいタスクを開始し、CountDownEvent と ManualResetEvent の組み合わせを使用して、それらが同時に開始されるようにします。
このタスクでは、バッファーを準備し、曲を再生する準備ができたことを CountDownEvent に通知します。その後、曲は ManualResetEvent からの信号を待ちます。CountDownEvent が各曲の準備が整ったという信号を受信すると、ManualResetEvent が通知され、SubmitSourceBuffer が呼び出されます。
10 回中 9 回の曲でサンプルの同期が開始されます (曲間のフェージングが検出されず、単純に音量が大きくなります) が、1 つがわずかにずれている場合があります。
詳細を説明するコードを次に示します。
Task playingtask = Task.Factory.StartNew(() =>
{
int nextbuffer = 0;
long zeroticks = MasterClock.Elapsed.Ticks;
try
{
while (true)
{
if (oursong.ADecoder == null || oursong.Status == PlaybackStatus.Stop) { break; }
var sampleiterator = oursong.ADecoder.GetSamples(TimeSpan.FromTicks(oursong.Position)).GetEnumerator();
while (true)
{
if (oursong.ADecoder == null || oursong.Status == PlaybackStatus.Stop) { break; }
foreach (SourceVoice SVoice in oursong.SVoices)
{
while (SVoice.State.BuffersQueued == oursong.BufferRing.Length && oursong.ADecoder != null)
{
BufferEndEvent.WaitOne(1);
}
}
if (!sampleiterator.MoveNext())
{
break;
}
var bufferpointer = sampleiterator.Current;
if (bufferpointer.Size > oursong.MBufferRing[nextbuffer].Size)
{
if (oursong.MBufferRing[nextbuffer].Pointer != IntPtr.Zero)
{
SharpDX.Utilities.FreeMemory(oursong.MBufferRing[nextbuffer].Pointer);
}
oursong.MBufferRing[nextbuffer].Pointer = SharpDX.Utilities.AllocateMemory(bufferpointer.Size);
oursong.MBufferRing[nextbuffer].Size = bufferpointer.Size;
}
SharpDX.Utilities.CopyMemory(oursong.MBufferRing[nextbuffer].Pointer, bufferpointer.Pointer, bufferpointer.Size);
oursong.BufferRing[nextbuffer].AudioDataPointer = oursong.MBufferRing[nextbuffer].Pointer;
oursong.BufferRing[nextbuffer].AudioBytes = bufferpointer.Size;
if (oursong.Status == PlaybackStatus.Ready)
{
CountDownEvent.Signal();
SongManualResetEvent.WaitOne();
oursong.Status = PlaybackStatus.Start;
}
foreach (SourceVoice SVoice in oursong.SVoices)
{
SVoice.SubmitSourceBuffer(oursong.BufferRing[nextbuffer], null);
}
oursong.Position += MasterClock.Elapsed.Ticks - zeroticks;
zeroticks = MasterClock.Elapsed.Ticks;
nextbuffer = ++nextbuffer % oursong.BufferRing.Length;
}
}
}
finally
{
DisposeAudio(oursong);
oursong.Position = oursong.Start;
}
}, TaskCreationOptions.LongRunning);
補足: foreach ステートメントを使用して、曲ごとに同じ順序で、各曲のバッファを複数のオーディオ デバイスに送信します。Ready 状態は、メモリ、オーディオデコーダなどをプリセットする load メソッドを使用して事前に設定されます。
操作セットを使用してソースボイスを同時に開始できることは知っていますが、別の方法 (クロックまたはその他の同期方法を使用) で、再生中の曲ごとにサンプルが同時に送信されるようにする方法はありますか?