1. 程式人生 > >[UWP] 用 AudioGraph 來增強 UWP 的音訊處理能力

[UWP] 用 AudioGraph 來增強 UWP 的音訊處理能力

Audio Graph

AudioGraph 是 Windows.Media.Audio 名稱空間下提供的音訊處理介面之一。

可以通過 AudioGraph 的靜態方法 CreateAsync 來例項化一個 AudioGraph 物件,例項化的時候需要傳入一個引數 AudioGraphSettings 來配置 AudioGraph。 Windows把系統中的音訊分成了大概12種類型:

public enum AudioRenderCategory
{
    Other = 0,
    ForegroundOnlyMedia = 1,
    BackgroundCapableMedia = 2,
    Communications = 3,
    Alerts = 4,
    SoundEffects = 5,
    GameEffects = 6,
    GameMedia = 7,
    GameChat = 8,
    Speech = 9,
    Movie = 10,
    Media = 11
}

在構造 AudioGraph 的時候選擇一種類別,可以應用 Windows 的一些優化措施(具體不知道)

建立 AudioGraph 程式碼如下:

private async Task InitAudioGraph()
{
    AudioGraphSettings settings = new AudioGraphSettings(Windows.Media.Render.AudioRenderCategory.Media);
    CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);
    if (result.Status == AudioGraphCreationStatus.Success)
    {
        audioGraph = result.Graph;
    }
}

Audio Graph 如何工作

在 Audio Graph 中,可以包含各種音訊節點,包括:

  • 音訊輸入節點(Input Node), DeviceInputNode, FileInputNode, MediaSourceInputNode,AudioFrameInputNode
  • 音訊輸出節點(Output Node), AudioSubmixNode
  • 中間節點(Submix Node), DeviceOutputNode, FileOutputNode, MediaSourceOutputNode,AudioFrameOutputNode

這三種類型的節點可以按照

輸入節點--->中間節點--->輸出節點

這種順序來組合,其中中間節點可以有多個,用來完成多級的音訊資料處理。

AudioGraph 中各個節點在處理音訊資料的時候,是分段處理的,把完整的音訊資料切分成一小段一小段來處理。

數字音樂存在取樣率的概念,比如48Khz,表示一秒取樣48000次,因此每一次取樣會有一個取樣得到取樣值Sample。

AudioGraph 在處理這些取樣值的時候,會將其分組,每一個分組為一個 Quantum,預設每一個Quantum 代表10ms, 因此針對48K取樣率的音訊,每一個Quantum會有480個Sample,也就是說每一次每個音訊節點只需要處理480個取樣值,針對這480個取樣值做各種處理,比如儲存,比如變換效果等。


音訊輸入節點(Input Node)

音訊輸入節點是為了獲取音訊資料,可以通過麥克風錄音,也可以直接從檔案讀取,也可以從一個網路流裡獲取,甚至可以直接自己生成一個AudioFrame,自己往裡面填音訊資料

1.DeviceInputNode

裝置輸入節點,實際上就是麥克風。

值得注意的是同一臺電腦上可能有多個音訊輸入裝置,如果在建立輸入節點時不指定使用的輸入裝置,將採用系統預設的。
Windows.Devices.Enumeration.DeviceInformation 下面的介面可以幫助我們選擇音訊輸入裝置

public IAsyncOperation<CreateAudioDeviceInputNodeResult> CreateDeviceInputNodeAsync(MediaCategory category,AudioEncodingProperties encodingProperties, DeviceInformation device);

2.FileInputNode

public IAsyncOperation<CreateAudioFileInputNodeResult> CreateFileInputNodeAsync(IStorageFile file);

支援的音訊格式有 MP3,wav,wma,m4a

在檔案輸入節點裡面,可以控制播放音訊的速度,音量和播放進度

3.MediaSourceInputNode

IAsyncOperation<CreateMediaSourceAudioInputNodeResult> CreateMediaSourceAudioInputNodeAsync(MediaSource mediaSource);

MediaSource可以從多個途徑獲得,比如檔案,比如網路流等,MediaSource類有許多的靜態方法可以建立MediaSource物件,比如檔案,好處是播放穩定,網路流的話會受網路影響,可能中斷

4.AudioFrameInputNode

個人認為這個輸入節點非常實用,用於建立音訊資源和編輯音訊會特別方便,因為它允許我們自己填充需要播放的音訊資料,介面本身不難,難點是如何生成可以播放的音訊資料。

想要讀寫一個AudioFrame中資料,需要使用 COM 介面IMemoryBufferByteAccess

[ComImport]
[Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
    void GetBuffer(out byte* buffer, out uint capacity);
}

因為 UWP 本質上就是 各種COM介面組成,在這種場景下直接使用 COM 可能有效率方面的考慮


音訊輸出節點(Output Node)

與輸入節點對應,存在各自的輸入節點(MediaSourceInputNode除外)

  1. DeviceInputNode, 代表揚聲器
  2. FileInputNode, 代表檔案,輸出音訊資料到檔案
  3. AudioFrameOutputNode, 這個應用場景我不是很明白,MSDN上這麼說:

    “An example scenario for this is performing signal analysis on the audio output”


中間節點(混音節點 Submix Node)

所有的輸入節點,都有一個介面叫做:

 public void AddOutgoingConnection(IAudioNode destination);

通過這個介面,可以把輸入節點和輸出節點連線起來,最簡單的,

fileInputNode.AddOutgoingConnection(deviceOutputNode);

這麼簡單一句,就實現了音樂播放,但是如果想做一些混音的話,就不是很方便了,所以需要 Submix Node.

fileInputNode.AddOutgoingConnection(submixNode);

deviceInputNode.AddOutgoingConnection(submixNode);

submixNode.AddOutgoingConnection(deviceOutputNode);

這三句程式碼,可以實現把音樂檔案和錄音直接混合輸出到揚聲器,當然也可以輸出到檔案中。


使用場景

Audio Graph 對 UWP 處理音訊的能力是一次不錯的拓展,基於 Audio Graph,有很多好玩的使用場景,比如官方文件裡面介紹到的空間音效 Spatial Audio.

目前我自己最簡單能想到到就是可以用這個做一個簡單的電臺主播助手APP,如圖:

簡易電臺主播助手


參考

本文基本來自於微軟官方文件:

Audio Graph

其中 Spatial Audio 部分的應用本文沒有介紹到,這部分需要一定的聲學知識才能玩得轉!

後續會繼續把自己對 UWP Audio 的學習記錄在部落格園