窗口刷新音频
Posted
技术标签:
【中文标题】窗口刷新音频【英文标题】:Window Refresh Audio 【发布时间】:2014-02-13 03:14:51 【问题描述】:所以我有点问题,我正在编写一个拍手传感器,当有人拍手并执行某个命令时它会听到。
//CLAP
private float bigValue;
WaveIn waveIn;
private double MaxValue;
private void button1_Loaded(object sender, RoutedEventArgs e)
if (Convert.ToInt16(textBox1.Text) > 100)
MessageBox.Show("Invalid Value");
return;
else
MaxValue = Convert.ToDouble(textBox1.Text) / 100;
bigValue = 0;
waveIn = new WaveIn();
int waveInDevices = waveIn.DeviceNumber;
//Get Device Count
for ( int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
waveIn.DeviceNumber = 0;
waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
int sampleRate = 8000;
int channels = 1;
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
//CLAP
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
for (int index = 0; index < e.BytesRecorded; index += 2)
short sample = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);
float sample32 = sample / 32768f;
label1.Content = sample32.ToString();
if (bigValue < sample32)
bigValue = sample32;
label2.Content = bigValue.ToString();
if (bigValue > MaxValue)
waveIn.StopRecording();
SendMessage(MONITOR_ON, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_ON);
MessageBox.Show("Did you Clap?");
代码本身按原样工作,但我需要它能够根据需要多次重置。这个程序基本上是听一个拍手声,然后唤醒显示器并启动它。每当我添加另一个“waveIn.StartRecording();”时,程序就会中断
关于如何刷新页面或让它永远收听的任何想法?
【问题讨论】:
您可能需要将WaveIn
代码移动到后端线程(BackgroundWorker),它只会在检测到拍手时在主线程上触发一个事件,但始终保持监听。
你能给我一个例子来说明如何做到这一点
我会使用 WasapiCapture 而不是 WaveIn。 WaveIn 已经过时了。 Wasapi 是一个相当新的 api,自 windows vista 以来所有 windows 系统都支持它。
【参考方案1】:
基本上您的代码所做的是打开waveIn
以接收音频数据,然后检查数据中的大声 样本。当它接收到超过阈值的样本时,它会停止侦听并发出命令。
正如所写,代码在检测到第一个大样本后停止。不再接收音频数据等。可能不是您想要的。相反,您需要改进您的拍手检测,以便它在检测到第一个大样本后停止处理传入的数据一段时间 - 比如说几秒钟。不要停止接收音频数据,只是停止对其做出反应。
向您的类添加一个DataTime
字段,用于记录最后一次拍手检测的时间戳。在您的 waveIn_DataAvailable
方法开始时,检查自上次检测以来经过的时间是否小于您的静音时间,如果是,则直接返回而不处理音频块。当您检测到足够大的样本时,触发事件并更新最后拍手检测字段。
类似这样的:
DateTime LastDetection = DateTime.Now.AddMinutes(-1);
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
if (LastDetection.AddSeconds(3) >= DateTime.Now)
return;
if (DetectClap(e.Buffer))
LastDetection = DateTime.Now;
SendMessage(MONITOR_ON, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_ON);
MessageBox.Show("Clap detected.");
bool DetectClap(byte[] audiobytes)
for (int i = 0; i < audiobytes.Length; i += 2)
float sample32 = (float)((short)((audiobytes[0] << 8) | audiobytes[1]))/32768f;
if (sample32 > MaxValue)
return true;
return false;
【讨论】:
【参考方案2】:这是一个将WaveIn
逻辑移动到后台线程的示例。它应该给你足够的开始。请查看documentation 以获取包含后台线程取消的完整示例。
//CLAP
private float bigValue;
WaveIn waveIn;
private double MaxValue;
private BackgroundWorker worker;
private void button1_Loaded(object sender, RoutedEventArgs e)
if (Convert.ToInt16(textBox1.Text) > 100)
MessageBox.Show("Invalid Value");
return;
else
MaxValue = Convert.ToDouble(textBox1.Text) / 100;
bigValue = 0;
// You'll need to handle the thread cancellation
// when the user clicks the button again
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += (s, e) =>
waveIn = new WaveIn();
int waveInDevices = waveIn.DeviceNumber;
//Get Device Count
for ( int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
waveIn.DeviceNumber = 0;
waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
int sampleRate = 8000;
int channels = 1;
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
;
worker.ProgressChanged += (s, e) =>
SendMessage(MONITOR_ON, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_ON);
MessageBox.Show("Did you Clap?");
;
worker.RunWorkerAsync();
//CLAP
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
for (int index = 0; index < e.BytesRecorded; index += 2)
short sample = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);
float sample32 = sample / 32768f;
label1.Content = sample32.ToString();
if (bigValue < sample32)
bigValue = sample32;
label2.Content = bigValue.ToString();
if (bigValue > MaxValue)
worker.ReportProgress(0);
break;
【讨论】:
按钮是否需要它,因为我在加载事件而不是点击事件上执行此操作 好的。不需要取消代码,除非您需要在表单关闭时释放非托管资源。【参考方案3】:所以最后我采用了与两个建议的答案不同的方式。
private float bigValue;
WaveIn waveIn;
private double MaxValue;
private void button1_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
if (Convert.ToInt16(textBox1.Text) > 100)
MessageBox.Show("Invalid Value");
return;
else
MaxValue = Convert.ToDouble(textBox1.Text) / 100;
bigValue = 0;
waveIn = new WaveIn();
int waveInDevices = waveIn.DeviceNumber;
//Get Device Count
for (int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
waveIn.DeviceNumber = 0;
waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
int sampleRate = 8000;
int channels = 1;
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
private void button1_Loaded(object sender, RoutedEventArgs e)
if (Convert.ToInt16(textBox1.Text) > 100)
MessageBox.Show("Invalid Value");
return;
else
MaxValue = Convert.ToDouble(textBox1.Text) / 100;
bigValue = 0;
waveIn = new WaveIn();
int waveInDevices = waveIn.DeviceNumber;
for (int i = 0; i <= 100; i++)
//Get Device Count
for (int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
waveIn.DeviceNumber = 0;
waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
int sampleRate = 8000;
int channels = 1;
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
int i = 0;
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
for (int index = 0; index < e.BytesRecorded; index += 2)
short sample = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);
float sample32 = sample / 32768f;
label1.Content = sample32.ToString();
if (bigValue < sample32)
bigValue = sample32;
label2.Content = bigValue.ToString();
if (bigValue > MaxValue)
waveIn.StopRecording();
if (IsOdd(i))
button1.IsEnabled = false;
else
button1.IsEnabled = true;
MessageBox.Show("Did you Clap?");
i++;
public static bool IsOdd(int value)
return value % 2 != 0;
第一个加载事件将其关闭。第二个使用 IsEnabled 事件在按钮打开和按钮关闭之间来回切换。 on 和 off 由 and if 语句在奇数和偶数之间进行选择来实现。
这就是我实现这个无限循环的方法。
注意:这种方式可能不是最有效的方式,但它完成了工作。 我也将(打开窗口)代码从这个答案中删除了。
【讨论】:
以上是关于窗口刷新音频的主要内容,如果未能解决你的问题,请参考以下文章