iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#使用 NAudio 实现音频可视化的方法
  • 913
分享到

C#使用 NAudio 实现音频可视化的方法

2024-04-02 19:04:59 913人浏览 薄情痞子
摘要

预览: 捕捉声卡输出: 实现音频可视化, 第一步就是获得音频采样, 这里我们选择使用计算机正在播放的音频作为采样源进行处理: NAudio 中, 可以借助 WasapiLoopba

预览:

捕捉声卡输出:

实现音频可视化, 第一步就是获得音频采样, 这里我们选择使用计算机正在播放的音频作为采样源进行处理:

NAudio 中, 可以借助 WasapiLoopbackCapture 来进行捕捉:


WasapiLoopbackCapture cap = new WasapiLoopbackCapture();
cap.DataAvailable += (sender, e) =>      // 录制数据可用时触发此事件, 参数中包含音频数据
{
    float[] allSamples = Enumerable      // 提取数据中的采样
        .Range(0, e.BytesRecorded / 4)   // 除以四是因为, 缓冲区内每 4 个字节构成一个浮点数, 一个浮点数是一个采样
        .Select(i => BitConverter.ToSingle(e.Buffer, i * 4))  // 转换为 float
        .ToArray();    // 转换为数组
    // 获取采样后, 在这里进行详细处理
}
cap.StartRecording();   // 开始录制

分离左右通道:

获取完采样后, 我们还需要对采样进行一点小处理, 因为捕获的数据是分通道的, 一般是左右声道:


// 设定我们已经将刚刚的采样保存到了变量 AllSamples 中, 类型为 float[]
int channelCount = cap.WaveFORMat.Channels;   // WasapiLoopbackCapture 的 WaveFormat 指定了当前声音的波形格式, 其中包含就通道数
float[][] channelSamples = Enumerable
    .Range(0, channelCount)
    .Select(channel => Enumerable
        .Range(0, AllSamples.Length / channelCount)
        .Select(i => AllSamples[channel + i * channelCount])
        .ToArray())
    .ToArray();

取通道平均值

将采样分为一个个通道的采样后, 我们可以将其合并, 取平均值, 以便于绘制:


// 设定我们已经将分开了的采样保存到了变量 ChannelSamples 中, 类型为 float[][]
// 例如通道数为2, 那么左声道的采样为 ChannelSamples[0], 右声道为 ChannelSamples[1]
float[] averageSamples = Enumerable
    .Range(0, AllSamples.Length / channelCount)
    .Select(index => Enumerable
        .Range(0, channelCount)
        .Select(channel => ChannelSamples[channel][index])
        .Average())
    .ToArray();

绘制时域图象:

处理刚刚的采样后, 你可以直接将其作为数据绘制到窗口中, 这即是时域图象, 这里使用最简单的折线绘制.


// 设定 g 为窗口的 Graphics 对象, windowHeight 为窗口的显示区域高度
// 设定通道采样平均值为 AverageSamples, 类型为 float[]
Point[] points = AverageSamples
    .Select((v, i) => new Point(i, windowHeight - v))
    .ToArray();   // 将数据转换为一个个的坐标点
g.DrawLines(Pens.Black, points);   // 连接这些点, 画线

傅里叶变换:

NAudio 中还提供了快速傅里叶变换的方法, 通过傅里叶变换, 可以将时域数据转换为频域数据, 也就是我们所说的频谱


// 我们将对 AverageSamples 进行傅里叶变换, 得到一个复数数组

// 因为对于快速傅里叶变换算法, 需要数据长度为 2 的 n 次方, 这里进行
float log = Math.Ceiling(Math.Log(AverageSamples.Length, 2));   // 取对数并向上取整
int newLen = (int)Math.Pow(2, log);                             // 计算新长度
float[] filledSamples = new float[newLen];
Array.Copy(AverageSamples, filledSamples, AverageSamples.Length);   // 拷贝到新数组
Complex[] complexSrc = filledSamples
    .Select(v => new Complex(){ X = v })        // 将采样转换为复数
    .ToArray();
FastFourierTransform(false, log, complexSrc);   // 进行傅里叶变换

// 变换之后, complexSrc 则已经被处理过, 其中存储了频域信息

分析频域信息:

对于傅里叶变换的频域信息, 需要稍加处理才可以方便的使用, 首先是提取有用的信息:


// NAudio 的傅里叶变换结果中, 似乎不存在直流分量(这使我们的处理更加方便了), 但它也是有共轭什么的(也就是数据左右对称, 只有一半是有用的)
// 仍然使用刚刚的 complexSrc 作为变换结果, 它的类型是 Complex[]

Complex[] halfData = complexSrc
    .Take(complexSrc.Length / 2)
    .ToArray();    // 一半的数据
float[] dftData = halfData
    .Select(v => Math.Sqrt(v.X * v.X + v.Y * v.Y))  // 取复数的模
    .ToArray();    // 将复数结果转换为我们所需要的频率幅度

// 其实, 到这里你完全可以把这些数据绘制到窗口上, 这已经算是频域图象了, 但是对于音乐可视化来讲, 某些频率的数据我们完全不需要
// 例如 10000Hz 的频率, 我们完全没必要去绘制它, 取 最小频率 ~ 2500Hz 足矣
// 对于变换结果, 每两个数据之间所差的频率计算公式为 采样率/采样数, 那么我们要取的个数也可以由 2500 / (采样率 / 采样数) 来得出
int count = 2500 / (cap.WaveFormat.SampleRate / filledSamples.Length);
float[] finalData = dftData.Take(count).ToArray();

绘制频域图象:

得到上面分析后的 finalData 后, 我们就可以直接绘制出来了, 这次使用柔和的曲线绘制


// 设定 g 为窗口的 Graphics 对象, height 为窗口高度
PointF[] points = finalData
    .Select((v, i) => new PointF(i, height - v))
    .ToArray();
g.DrawCurve(Pens.Purple, points);    // Graphics 可以直接绘制曲线

更优的绘制:

上面的时域和频域图象, 我们都是一股脑的将数据的索引作为 X 坐标, 窗口高度减去数据值作为 Y 坐标, 有两个突出的问题:

  • 数据可能无法填满窗口的宽度或者超出窗口的宽度范围
  • 数据太大时, 也会导致绘制的线条超出窗口高度

第一个问题好解决, 直接使索引所占数据长度的百分比恰好等于 X 坐标相对于窗口宽度的百分比即可:

\[x = index \div dataLength * windowWidth\]

对于第二个问题, 有两个解决方案, 一是直接为数据加权重, 例如统一乘 0.5, 使数据减小一节, 二就是套一个函数, 例如 log 函数, 毕竟 log 函数在较高自变量的情况下, 因变量的变化趋势越来越小, 我们只需要对这个 log 函数进行稍加处理, 就可以直接应用到数据变换数据上, 使其不超出窗口绘图区域

另外, 我们也可以平滑频谱显示(指动画变换), 它的原理大概是这样:

  • 例如这次进行傅里叶变换的结果是: {0, 100, 50},
  • 下一次傅里叶变换的结果是: {100, 0, 0},
  • 可以得出, 增量为: {100, -100, -50},
  • 在更新变换结果时, 我们不再直接将新的结果替换旧的结果, 而是在旧的结果的基础上, 加上增量×权重
  • 例如权重是 0.5 时, 那么实际增量是: {50, -50, -25},
  • 那么实际新的值是: {50, 50, 25},
  • 如果下一次变换的结果还是 {100, 0, 0}, 那我们再次从 {50, 50, 25} 向新值逼近, 权重仍然是 0.5, 那么实际增量是: {25, -25, -12.5},

注意到了吗? 这次的增量是上次增量的一半, 这正好是一个减速运动, 而且新值与旧值的差越大, 变化的就越快, 而它们会不断重合, 因而速度不断变慢, 形成减速运动的频谱图.

更多内容:

更多关于 NAudio 的使用, 可以看这篇文章:[C#] NAudio 的各种常见使用方式 播放 录制 转码 音频可视化

项目开源:

关于本文章涉及的大部分内容, 均在 GitHub.com/SlimeNull/AudioTest 仓库中的 Null.AudioVisualizer 项目中有写. (注释妥当了)

其实音频可视化我老早就想做了, 但是本人数学不是非常的好, 不过最后总算是坚持下来了, 弄出来了啊, 心情老激动了

到此这篇关于[C#] 使用 NAudio 实现音频可视化的文章就介绍到这了,更多相关C#音频可视化内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C#使用 NAudio 实现音频可视化的方法

本文链接: https://www.lsjlt.com/news/125468.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C#使用 NAudio 实现音频可视化的方法
    预览: 捕捉声卡输出: 实现音频可视化, 第一步就是获得音频采样, 这里我们选择使用计算机正在播放的音频作为采样源进行处理: NAudio 中, 可以借助 WasapiLoopba...
    99+
    2024-04-02
  • C#如何使用NAudio实现音频可视化
    小编给大家分享一下C#如何使用NAudio实现音频可视化,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!预览:捕捉声卡输出:实现音频可视化, 第一步就是获得音频采样...
    99+
    2023-06-15
  • C# NAudio 库的各种常见使用方式之播放 录制 转码 音频可视化
    概述 在 NAudio 中, 常用类型有 WaveIn, WaveOut, WaveStream, WaveFileWriter, WaveFileReader, AudioFile...
    99+
    2024-04-02
  • Python使用ffmpeg合成视频、音频的实现方法
    最近有在使用屏幕录制软件录制桌面,在用的过程中突发奇想,使用python能不能做屏幕录制工具,也锻炼下自己的动手能力。接下准备写使用python如何做屏幕录制工具的系列文章: 录制屏...
    99+
    2024-04-02
  • JS如使用音频可视化插件Wavesurfer.js
    这篇文章主要为大家展示了“JS如使用音频可视化插件Wavesurfer.js”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JS如使用音频可视化插件Wavesur...
    99+
    2024-04-02
  • 前端音频可视化Web Audio如何实现
    这篇文章主要介绍“前端音频可视化Web Audio如何实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“前端音频可视化Web Audio如何实现”文章能帮助大家解决问题。实现思路...
    99+
    2023-07-05
  • Android 音频可视化:频谱特效的探索与实践
    音频可视化,一言以蔽之,就是声音到图像的转换。 随着视觉工业时代的到来,用户逐渐重视产品的极致体验,在市场上诸多优秀的音乐类APP中,频谱动效 是一个经典的应用场景: 图片来源:咪咕音乐 本文...
    99+
    2023-09-16
    android 音视频
  • 前端音频可视化Web Audio实现示例详解
    目录背景实现思路实现一、频率图二、实时频率图关于请求音频跨域问题解决方案总结背景 最近听音乐的时候,看到各种动效,突然好奇这些音频数据是如何获取并展示出来的,于是花了几天功夫去研究...
    99+
    2023-03-09
    Web Audio音频可视化 Web Audio
  • vue使用wavesurfer.js解决音频可视化播放问题
    目录1.安装wavesurfer2.在页面导入3.上源码4.注释:之前给大家介绍过vue中音频wavesurfer.js的使用方法,感兴趣的朋友可以点击查看,今天继续给大家普及vue...
    99+
    2024-04-02
  • 使用Golang和FFmpeg实现视频画质优化的方法
    要使用Golang和FFmpeg来实现视频画质优化,你可以使用FFmpeg的命令行工具来进行视频处理,并在Golang中调用这些命令...
    99+
    2023-10-08
    Golang
  • C#调用FFmpeg操作音视频的实现示例
    目录项目背景FFmpeg介绍FFmpeg相关教程博客示例源码下载FFmpeg.exe安装包C#进程调用FFmpeg操作音视频项目背景   因为公司需要对音视频做一些操作,比如说对系统...
    99+
    2024-04-02
  • 怎么使用Python自动化实现抖音自动刷视频
    这篇文章主要介绍了怎么使用Python自动化实现抖音自动刷视频的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么使用Python自动化实现抖音自动刷视频文章都会有所收获,下面我们一起来看看吧。环境准备Pytho...
    99+
    2023-07-05
  • Pytorch可视化的几种实现方法
    目录一,利用 tensorboardX 可视化网络结构二,利用 vistom 可视化三,利用pytorchviz可视化网络结构一,利用 tensorboardX 可视化网络结构 参...
    99+
    2024-04-02
  • vue怎么使用wavesurfer.js解决音频可视化播放问题
    这篇文章主要介绍“vue怎么使用wavesurfer.js解决音频可视化播放问题”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue怎么使用wavesurfer.js解决音频可视化播放问题”文章能帮...
    99+
    2023-06-29
  • Vue使用Echarts实现数据可视化的方法详解
    目录一,Echarts1.1 获取ECharts1.2 引入 ECharts二,Vue使用Echarts2.1 Vue环境2.2 main.js引入Echarts2.3 使用模板2....
    99+
    2024-04-02
  • 使用Golang和FFmpeg实现视频剪辑的方法
    要使用Golang和FFmpeg实现视频剪辑,可以通过调用FFmpeg的命令行工具来完成操作。下面是一个示例的代码:gopackag...
    99+
    2023-10-20
    Golang
  • C# wpf 通过HwndHost渲染视频的实现方法
    目录前言一、如何实现二、使用方式三、示例总结前言 日常开发中,特别是音视频开发,需要在界面上渲染视频,比如制作一个播放器、或者视频编辑工具、以及视频会议客户端。通常拿到的是像素格式数...
    99+
    2024-04-02
  • C#实现提取Word中插入的多媒体文件(视频,音频)
    目录dll文件安装(3种方法)提取文件完整代码C#VB.NET在Word中可将文件通过OLE对象嵌入的方式插入到文档,包括Word、excel、PDF、PPT、图片、宏文件、文件包等...
    99+
    2024-04-02
  • Docker下使用Elasticsearch可视化Kibana的方法
    这篇文章将为大家详细讲解有关Docker下使用Elasticsearch可视化Kibana的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。使用教程在这里我们使用linux系统作为演示系统:fedora...
    99+
    2023-06-07
  • Vue使用echarts可视化组件的方法
    echarts组件官网地址:https://echarts.apache.org/examples/zh/index.html 1.找到脚手架项目所在地址,执行cnpm instal...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作