[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 的学习记录在博客园

posted @ 2018-11-30 00:31  DemoApp  阅读(1280)  评论(3编辑  收藏  举报