与音频流并行操作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
之后的事件中看到的那样,我想对队列进行一些处理。我担心在处理数据时,新的样本会从声卡传来,我的处理会丢失。
- 正确的方法是什么?
- 我从事件中调用的处理是静态的吗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) { }
}
}
}
我用 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
之后的事件中看到的那样,我想对队列进行一些处理。我担心在处理数据时,新的样本会从声卡传来,我的处理会丢失。
- 正确的方法是什么?
- 我从事件中调用的处理是静态的吗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) { }
}
}
}