2

NAudio を Reactive Extentions と組み合わせようとしていますが、NAudio でオーディオを再生するのに問題があります。

これまでの私のコードは次のとおりです。

 public class WaveOutPlayer : IDisposable
{
    WaveOut wavOut = new WaveOut(WaveCallbackInfo.FunctionCallback());

    public WaveOutPlayer(int device, int sampleRate, int channels, IStereoSource source)
    {
        var provider = new WavProv(source, sampleRate, channels);
        provider.SetWaveFormat(sampleRate,channels);

        wavOut.Init(provider);
    }

    private class WavProv : WaveProvider32
    {
        AutoResetEvent are = new AutoResetEvent(false);
        ConcurrentQueue<float> queue = new ConcurrentQueue<float>();

        public WavProv(IStereoSource source, int sampleRate, int channels)
        {
            source.ChannelLeft
           .Zip(source.ChannelRight, (ls, rs) => new double[] { ls, rs })      //one sample from each channel
           .SelectMany(samps => samps)                                         //convert to samples array l,r,l,r,l
           .Buffer(sampleRate * channels * 1)                                     //buffer samplerate*channels*2 seconds
           .Select(x => x.ToArray())                                            // to observable of chunks
           .Do(x => { are.Set(); })
           .SubscribeOn(NewThreadScheduler.Default)
           .Subscribe(data =>
           {
               //queue.Enqueue((float)data);
               data.ToList().ForEach((x) => queue.Enqueue((float)x));
           });

        }

        public override int Read(float[] buffer, int offset, int sampleCount) 
        {
            int itemsRead;

            if (!queue.Any())                                                    //No data in the queue
            {
                //are.WaitOne();
                buffer = Enumerable.Repeat(0.0f, sampleCount).ToArray();        //Wait for some data
                itemsRead = sampleCount;
            }
            else
            {

                //number of items to read is lower of  samplecount or items in queue
                int itemsToRead = (queue.Count() > sampleCount) ? sampleCount : queue.Count();

                for (itemsRead = 0; itemsRead < itemsToRead; itemsRead++)
                {
                    float res;
                    if(queue.TryDequeue(out res))
                        buffer[itemsRead + offset] = res;       //add items from queue to buffer
                }
            }
            Console.WriteLine("Requested:{0}, Read: {1}",sampleCount, itemsRead);
            return itemsRead;
        }
    }

    public void Play()
    {
        wavOut.Play();
    }

    public void Dispose()
    {
        wavOut.Dispose();
    }
}

Read メソッドが呼び出され、Console.WriteLine は、常に十分なデータを提供していることを示しています。ちなみに、信号の生成を遅くして、時々すべてゼロのバッファを提供する必要がある場合 (コードは現在存在しません)、「カチッ」という音がします。

私が見逃した他の問題/落とし穴はありますか?

たとえば、振幅範囲は 0 ~ 1 のみですか、それとも float の全範囲をサポートしていますか?

ありがとう

4

1 に答える 1

3

BufferedWaveProviderリセット イベント/キュー全体ではなく、NAudio を使用することをお勧めします。このようなシナリオのために設計されました。

プレーヤーのバッファが突然不足すると、中断が発生します。データのストリーミング速度が十分ではありません。

次に、関数のシグネチャを明確にします。

int Read(float[] buffer, int offset, int sampleCount)

バッファ、バッファ内のオフセット、およびチャンク サイズが提供されます。返された値は、この読み取り操作で指定できるアイテムの数を示しています。要求されたサンプルに対応する正確なバイト数を指定する必要はありません

したがって、無音を提供したい場合は、ゼロのバッファーを作成して返すのではなく、読み取り長として単に 0 を返します。

最後に、急激なカットオフを望まない場合は、サンプルの最後のセットの振幅をゆっくりと減少させることができます。これは(N - n) / N(n ϵ [0, N]) を掛けるだけの簡単なものです。バッファ アンダーランによる切断は、まったく別の問題です。

注意

現在のソリューションは、本番環境でこれを行うには良い方法ではないことを付け加えさせてください。間に多くのオブジェクトを使用すると、ガベージ コレクションがノックしたときに、最終的に多くの遅延の問題が発生します。NAudio の作成者である Mark Heath は、ガベージ コレクションを最小限に抑えるために、バッファーや EventArgs などを再利用するなど、多くのトリックを使用しているため、無駄になるのは不当です。

于 2012-07-11T21:49:00.517 に答える