Windows Phone - 擷取麥克風輸入的音量觸發任務

Windows Phone - 擷取麥克風輸入的音量觸發任務

在<Windows Phone 7 – 寫一個會Record Audio的錄音程式>這篇介紹過怎麼操作麥克風來做到錄音的功能。

如果忘記了Microsoft.Xna.Framework.Audio.Microphone該類別的一些特性,可以透過上述該篇內容加以了解。

 

本篇則介紹如何透過麥克風取得目前輸入的音量來觸發任務。為什麼會想介紹這個呢?主要是因為很好奇

看到很多透過麥克風呼氣或尖叫音量來觸發遊戲或特別的任務,因此,也來看看在WP裡如何實作吧。

 

[步驟]

0. 至WMAppManifest.xml開啟「ID_CAP_MICROPHONE」的權限;

 

1. 設定MainPage.xaml畫面,用來呈現音量變化有一個音量軸的高度變化與數值呈現,如下圖:

    005006

    那麼他的XAML檔設定如下:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="30*" />
        <RowDefinition Height="70*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="30*" />
        <ColumnDefinition Width="70*" />
    </Grid.ColumnDefinitions>
    <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
        <Button x:Name="btnStart" 
                Content="Start"
                Click="recordButton_Click" />
        <Button x:Name="btnStop"
                Content="Stop"
                Click="stopButton_Click" />
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Volume: "
                  FontSize="30"
                  HorizontalAlignment="Center"
                  VerticalAlignment="Center"
                  Margin="30,0, 30, 0"     />
            <TextBlock Name="txtVolume" 
               FontSize="30"
               HorizontalAlignment="Center"
               Text="0" />
        </StackPanel>
    </StackPanel>
    <!-- 音量呈現軸 -->
    <Rectangle 
               Grid.Column="0" 
               Grid.Row="1" 
        Fill="#FFF90606" 
               HorizontalAlignment="Center"
               Height="5" 
               Stroke="Black" 
               VerticalAlignment="Bottom"
               Width="100"
               x:Name="rectVolume">
    </Rectangle>
    <!-- 放置擷取的數值 -->
    <ListBox 
        Grid.Row="1"
        Grid.Column="1"
        Height="415"
        x:Name="lstVolume" />
</Grid>

   宣告了一個<Rectangle />用來呈現音量軸,所以當用戶輸入的音量達到我們最低標記時,則會調整該軸的高度來呈現效果。

 

 

2. 參考<How to access the microphone in a Windows Phone app>的內容建立一個可以操作麥克風的應用程式;

 

    2-1. 準備必要的參數與Namespaces宣告;

//宣告必要的Namespaces
using System.Windows.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using System.Windows.Media;

 

public partial class MainPage : PhoneApplicationPage
{
    //宣告麥克風元件
    Microphone tMicrophone = Microphone.Default; 
    //放入可緩衝用的byte array
    byte[] buffer; 
    //放入可將byte寫入Stream
    MemoryStream stream = new MemoryStream(); 
    //播放所錄製聲音的元件
    SoundEffect sound;
    //宣告音量所達的最低指標,用於觸發任務
    private int minimumThreshold = 300;
 
}

 

 

    2-1. 註冊每固定時間更新,以確保錄音的功能持續的更新狀態與進行擷取動作,並註冊麥克風元件的BufferReady事件;

// Constructor
public MainPage()
{
    InitializeComponent();
 
    // Timer to o simulate the XNA Game Studio game 
    // loop (Microphone is from XNA Game Studio)
    DispatcherTimer dt = new DispatcherTimer();
    dt.Interval = TimeSpan.FromMilliseconds(33);
    dt.Tick += delegate
    {
        try { FrameworkDispatcher.Update(); }
        catch { }
    };
    dt.Start();
 
    //註冊擷取錄音緩衝的事件
    tMicrophone.BufferReady += new EventHandler<EventArgs>(microphone_BufferReady);
}

 

 

    2-2. 註冊開啟/關閉麥克風的事件處理;

private void recordButton_Click(object sender, RoutedEventArgs e)
{
    //識別如果目前麥克風是關閉的,則打開。
    if (tMicrophone.State == MicrophoneState.Stopped)
    {
        try
        {
            //指定麥克風元件緩衝多少區間,則觸發BufferReady事件
            //設定愈短,其效果比較明顯,但不一定比較好,請依需求調整。
            tMicrophone.BufferDuration = TimeSpan.FromMilliseconds(100);
            //設定緩衝用的byte array需要保留多少空間
            buffer = new byte[
            tMicrophone.GetSampleSizeInBytes(tMicrophone.BufferDuration)];
            //開始錄音
            tMicrophone.Start();
 
            System.Diagnostics.Debug.WriteLine("Threshold setted to:" + minimumThreshold);
        }
        catch (Exception ex)
        {
            string tMsg = ex.Message;
        }
        btnStart.IsEnabled = false;
        btnStop.IsEnabled = true;
    }
}

 

private void stopButton_Click(object sender, RoutedEventArgs e)
{
    //識別如果目前麥克風為開啟,則關閉
    if (tMicrophone.State == MicrophoneState.Started)
    {
        tMicrophone.Stop();
    }
    btnStart.IsEnabled = true;
    btnStop.IsEnabled = false;
    rectVolume.Height = 5;
    txtVolume.Text = "0";
    lstVolume.Items.Clear();
}

 

 

3. 註冊處理BufferReady的事件,從中識別輸入的音量是否超過設定的最低標記值,有則執行音量軸的變化

    為什麼需要最低標記值(minimumThreshold)?根據<How to access and manage the Microphone raw data in WP>的介紹,

最主要是為了讓低於最低標記值的音量變化不出現反應,這樣可以控制讓用戶的輸入一定要達我們的需求,

避免不必要的資訊被記錄到而反應邏輯或效果的判斷。

void microphone_BufferReady(object sender, EventArgs e)
{
    HandleVolume();
}
 
private void HandleVolume()
{
    // Retrieve audio data            
    tMicrophone.GetData(buffer);
    // RMS Method           
    double rms = 0;
    ushort byte1 = 0;
    ushort byte2 = 0;
    short value = 0;
    int volume = 0;
    rms = (short)(byte1 | (byte2 << 8));
    for (int i = 0; i < buffer.Length - 1; i += 2)
    {
        byte1 = buffer[i]; byte2 = buffer[i + 1];
        value = (short)(byte1 | (byte2 << 8));
        rms += Math.Pow(value, 2);
    }
    //取得RMS值與Volumne
    rms /= (double)(buffer.Length / 2);
    volume = (int)Math.Floor(Math.Sqrt(rms));
 
    //識別是否超過最低標記值
    if ((volume > minimumThreshold))
    {
        Dispatcher.BeginInvoke(() =>
        {
            txtVolume.Text = volume.ToString();
            lstVolume.Items.Add(string.Format("{0},{1}", buffer.Length.ToString(), volume.ToString()));
            //更新音量軸
            rectVolume.Height = (volume - minimumThreshold) * .6;
        });
 
        System.Diagnostics.Debug.WriteLine("Threshold exceeded");
        System.Diagnostics.Debug.WriteLine("buffer.Length" + buffer.Length + " Volume:" + volume);
    }
    else
    {
        //沒有則還原畫面值
        Dispatcher.BeginInvoke(() =>
        {
            rectVolume.Height = 5;
            txtVolume.Text = "0";
            lstVolume.Items.Clear();
        });
    }
}

其計算的公式採用:RMS method來加以算出Volume。

 

[範例程式]

======

以上是分享怎麼從過Microphone類別的BufferReady取得音量的變化,進一步就可以依需求來設定反應的對象。

希望對大家有所幫助。

 

References

How to access the microphone in a Windows Phone app

Windows Phone SDK 8.0 Extensions for XNA Game Studio 4.0

How to access and manage the Microphone raw data in WP & Using QMicrophone

Saving Microphone stream to wave format in Windows Phone

XNA from Silverlight on Windows Phone 7 – The Microphone

Windows Phone 7 – 寫一個會Record Audio的錄音程式

Part 24 - Windows Phone 7 - Microphone Repeater

進階音效控制與管理

 

Dotblogs 的標籤: