与音频流并行操作c#

parallel operations with audio stream c#

我用 c#(wpf) 录制声音,当来自声卡的数据可用时,它会调用此事件:

void myWaveIn_DataAvailable(object sender, WaveInEventArgs e)
    {
        for (int index = 0; index < e.BytesRecorded; index += 2)//Here I convert in a loop the stream into floating number samples
        {

            short sample = (short)((e.Buffer[index + 1] << 8) |
                                    e.Buffer[index + 0]); 
            samples32Queue.Enqueue(sample/32768f);
        }
        //***Do some Processing with data inside Queue
    }

如您所见,我将每个样本从记录的缓冲区推送到这样声明的队列中:

Queue<float> samples32Queue = new Queue<float>();

正如您在 for loop 之后的事件中看到的那样,我想对队列进行一些处理。我担心在处理数据时,新的样本会从声卡传来,我的处理会丢失。

  1. 正确的方法是什么?
  2. 我从事件中调用的处理是静态的吗method/non-static?

考虑到您可以缓冲样本并在以后处理它们,请考虑使用 BlockingCollection。 BlockingCollection 是生产者-消费者模式的绝佳解决方案,据我了解,这就是您的情况。一方面你有 myWaveIn_DataAvailable() 方法作为生产者向集合添加样本,另一方面你有另一个消费线程(但不一定是另一个线程)收集样本和处理他们。可以通过多种方式实现消费者,并且它们在 MSDN 中有详细记录。

编辑: 看下面的例子,我没有测试但它应该给你一个起点:

class ProducerConsumerExample
{
    BlockingCollection<float> samples32Collection;
    Thread consumer;
    public ProducerConsumerExample()
    {
        samples32Collection = new BlockingCollection<float>();
        consumer = new Thread(() => LaunchConsumer());
        consumer.Start();   //you don't have to luanch the consumer here...
    }
    void Terminate()    //Call this to terminate the consumer
    {
        consumer.Abort();
    }
    void myWaveIn_DataAvailable(object sender, WaveInEventArgs e)
    {
        for (int index = 0; index < e.BytesRecorded; index += 2)//Here I convert in a loop the stream into floating number samples
        {

            short sample = (short)((e.Buffer[index + 1] << 8) |
                                    e.Buffer[index + 0]);
            samples32Collection.Add(sample / 32768f);
        }
    }

    void LaunchConsumer()
    {
        while (true /* insert your abort condition here*/)
        {
            try
            {
                var sample = samples32Collection.Take();   //this thread will wait here until the producer add new item(s) to the collection
                Process(sample);    //in the meanwhile, more samples could be added to the collection 
                                    //but they will not be processed until this thread is done with Process(sample)
            }
            catch (InvalidOperationException) { }
        }
    }
}