说明
本文发布较早,查看 TypeScript 版本了解最新动态。(2021 年 5 月 注)
在线演示: 音频可视化(TypeScript)
准备
IDE:Visual Studio
Nuget包:SharpDx.XAudio2
Nuget包:Win2D.UWP
了解学习:Win2D 官方博客
了解学习:Win2D 官方示例
第一节 波形
获取实时时域数据。
Imports SharpDX.Multimedia Imports SharpDX.XAudio2 Public Class AudioPlayer Public Event WavePlaying(e As WavePlayingEventArgs) Public Property Device As XAudio2 Public Property Voice As SourceVoice Private CurrentFormat As WaveFormat Private CurrentBuffer As AudioBuffer Private PacketsInfo As UInteger() Public Sub New() Device = New XAudio2() Device.StartEngine() Dim mv As New MasteringVoice(Device) End Sub Public Async Function LoadFile(fileName As String) As Task(Of Boolean) Try Voice = Await CreateVoiceFromFile(Device, fileName) LoadBuffer() Return True Catch Return False End Try End Function Public Sub Play(Optional volume As Single = 1.0F) Voice?.SetVolume(volume) Voice?.Start() ReadBuffer() End Sub Public Sub [Stop]() Voice?.Stop() End Sub Protected Async Function CreateVoiceFromFile(device As XAudio2, fileName As String) As Task(Of SourceVoice) Dim file = Await Package.Current.InstalledLocation.GetFileAsync(fileName) Dim streamWithContentType = Await file.OpenReadAsync() Dim st = streamWithContentType.AsStreamForRead() Using stream = New SoundStream(st) CurrentFormat = stream.Format CurrentBuffer = New AudioBuffer() With { .Stream = stream.ToDataStream(), .AudioBytes = CInt(stream.Length), .Flags = BufferFlags.EndOfStream } PacketsInfo = stream.DecodedPacketsInfo End Using Dim sourceVoice = New SourceVoice(device, CurrentFormat, True) Return sourceVoice End Function Protected Sub LoadBuffer() Voice?.FlushSourceBuffers() Voice?.SubmitSourceBuffer(CurrentBuffer, PacketsInfo) End Sub ''' <summary> ''' 从流中读取当前播放的数据 ''' </summary> Private Async Sub ReadBuffer() Try Dim count As Integer = CurrentFormat?.AverageBytesPerSecond / 10 While Voice.State.BuffersQueued > 0 If Voice.State.SamplesPlayed * CurrentFormat.BlockAlign > CurrentBuffer.Stream.Position + count Then Dim byteArr(count - 1) As Byte Await CurrentBuffer.Stream.ReadAsync(byteArr, 0, count) RaiseEvent WavePlaying(New WavePlayingEventArgs(byteArr, CurrentFormat)) Else Await Task.Delay(10) End If End While Catch Return End Try End Sub Public Function Position() As Integer Return Voice.State.SamplesPlayed / CurrentFormat.SampleRate End Function Protected Overrides Sub Finalize() Try Dispose(False) Finally MyBase.Finalize() End Try End Sub Public Sub Dispose() Dispose(True) GC.SuppressFinalize(Me) End Sub Private Sub Dispose(isDisposing As Boolean) If Not isDisposing Then Return End If Voice.DestroyVoice() Voice.Dispose() CurrentBuffer.Stream.Dispose() End Sub End Class