2014-02-13 72 views
0

因此,我遇到了一些問題,我編寫了一個拍手傳感器,聽到有人拍手並執行某個命令時會聽到。窗口刷新音頻

 //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();」的任何時間

關於如何刷新頁面或讓它永遠聽音樂的任何想法?

+0

可能需要將'WaveIn'代碼移動到後端線程([BackgroundWorker](http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx)),它只是在檢測到拍手時在主線上觸發事件,但始終保持收聽。 – wdosanjos

+0

你可以給我一個例子,如何做到這一點 –

+0

我會使用WasapiCapture而不是WaveIn。 WaveIn已經過時了。 Wasapi是一個非常新的API,自Windows Vista以來,它在所有Windows系統上都得到支持。 –

回答

0

這是一個將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; 
      } 
     } 
    } 
} 
+0

是否需要使用按鈕,因爲即時消息在加載事件上執行而不是單擊事件 –

+0

確定。取消代碼將不是必需的,除非您需要在表單關閉時釋放非託管資源。 – wdosanjos

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; 
} 
0

所以最後我比都以不同的方式去參考答案。

 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事件在按鈕和按鈕之間返回。開啓和關閉通過和如果聲明選擇奇數和偶數。

這就是我如何實現這個無限循環。

注意:這種方式可能不是最有效的方式,但它完成了工作。 此外,我離開(打開窗口)代碼的這個答案。