- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Android Visualizer 可视化器的自定义实现由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
听音乐时,有时你会看到那些视觉上令人愉悦的跃动条,它们音量越大跳得越高。通常,左边的条形对应的频率较低(低音),而右边的条形对应较高的频率(高音):
这些跃动条通常被称为视觉均衡器或可视化器,若想在Android应用中展示类似的可视化效果,你可以使用Android原生的Visualizer类,它是Android框架中的一部分,且能够附加到你的AudioTrack.
它是切实有效的,但有一个重要的缺陷:它需要申请 麦克风权限 ,而从官方文档上来看,这是有确切考虑的:
问题是,用户不会允许音乐APP申请使用他们的麦克风权限(这毫无疑问)。而当我翻遍了Android官方提供的API或者其他三方库,却找不到实现这样可视化器效果的替代方案.
因此我考虑自己造轮子,第一个问题是,我需要思考如何将正在播放的音乐,转换成每个跳跃条对应的高度.
首先,让我们从输入开始。当数字化音频时,我们通常会对信号幅度进行非常频繁的采样,这称为脉冲编码调制 (PCM)。振幅随之被量化,我们将其表示到我们自己的数字标度上.
举个例子,如果编码是PCM-16,这个比例将是16 bit,我们可在2的16次幂的数字范围内表示一个幅度,即65536个不同的幅度值.
如果您在多个channel上采样(如立体声,分别录制左右声道),这些幅度会相互跟随,因此首先是 channel 0 的幅度,然后是 channel 1 的幅度,然后是 channel 0,依此类推。一旦我们获得了这些幅度值作为原始数据,我们就可以继续下一步。为此,我们需要了解声音实际上是什么:
我们听到的声音是物体振动的结果。例如人的声带、吉他的金属弦和木琴身。一般情况下,若不受特定声音振动的影响,空气分子会随机移动。选自《 Digital Sound and Music 》 。
当敲击音叉时,它会以非常特定的440次/秒 (Hz) 振动,这种振动将通过空气传播到耳膜,在那里以相同的频率共振,大脑会将其解释为音符A.
在PCM中,这可以表示为正弦波,每秒重复440次。这些波的高度不会改变音符,但它们代表振幅;通俗点说,就是当听到它时,你耳朵里的响度.
但是当听音乐时,通常不仅有正在听的音符A(虽然我希望这样),而且还有过多的乐器和声音,从而导致PCM图形对人眼没有意义。实际上它是不同频率和振幅的不同正弦波大量振动的组合.
即使是非常简单的PCM信号(例如方波)在解构为不同的正弦波时也非常复杂:
方波解构为近似正弦和余弦波.
幸运的是,我们有算法来进行这种解构,我们称之为傅立叶变换 。正如上文可视化器所展示的,它实际上是从正弦波和余弦波的组合中解构而出的。余弦基本上是一个 延迟 的正弦波,但是在这个算法中拥有它们非常有用,否则我们将无法为点0创建一个值,因为每个正弦波都是从0开始的,相乘仍然会得到0.
执行傅里叶变换的算法之一是 快速傅里叶变换 (FFT)。在我们的PCM声音数据上运行此FFT算法时,我们将获得每个正弦波的幅度列表。这些波是声音的频率。在列表的开头,我们可以找到低频(低音),最后是高频(高音).
这样,我们通过绘制一个这样的条形图,其高度由每个频率的幅度决定——我们得到了我们想要的可视化器.
现在回到Android。首先,我们需要音频的PCM数据。为此,我们可以将AudioProcessor配置给到我们的ExoPlayer实例,它会在转发之前接收每个音频字节。您还可以进行修改,例如更改幅度或过滤通道,但不是现在.
在queueInput(inputBuffer: ByteBuffer)方法中,我们将收到捆在一起作为一帧的byte数据.
这些 byte 可能来自多个 channel,为此我取了所有 channel 的平均值,并且仅将其转发以进行处理.
为了使用傅立叶变换,我使用了Noise库。变换需要一个具有给定样本大小的float列表。样本大小应该是2的因子,我选择了4096.
增加这个数字可获得更精细的数据,但计算时间更长,计算也更不频繁(因为可针对每 X 字节的声音数据进行一次更新,其中X是样本大小)。如果数据是PCM-16,则2个字节构成一个幅度。浮点值并不重要,因为它们可以缩放。如果您提交一个介于0和1之间的数字,则结果都将介于0和1之间(因为无需将正弦波幅度与更高的数字相乘).
所得结果也将是一个float列表。我们可使用这些频率立即绘制 4096 个条形图,但这不切实际.
来看看如何改进这些结果数据.
首先,我们可以将这些频率组合成更小的组。因此,假设我们将0-20kHz频谱划分为20个小节,每个小节跨越1kHz.
20条比4096条更容易绘制,我们也无需那么多条。如果现在绘制这些值,可以看到,只有最左边的部分在大幅度移动.
这是因为音乐中频率的适用范围大约是20-5000Hz,而听10kHz的声音会让人很烦躁。若将音乐中的较高频率排除在外,你会注意到,它听起来会越来越沉闷,但与较低频率相比,这些频率的幅度非常小.
如果你看过录音室均衡器,则会发现频段也分布不均,频率的下半部分通常占用80-90%的频段:
鉴于此,建议通过为较低频率分配更多频带来使这些频带具有可变宽度。下图是这样做的效果,它看起来会好一些:
似乎不错,但仍然存在2个问题:
首先,右边的频率似乎移动得有点太多了。这是因为我们的采样并不完美,它引入了称为频谱泄漏的伪像,其中原始频率会涂抹到相邻的频率中。为了减少这种拖尾现象,我们可以应用一个窗口函数,在那里我们突出我们感兴趣的频率并调低其他频率。这些窗口有不同类型,但我将使用汉明窗口 (Hamming-window)。我们感兴趣的频率是中间的频段,并针对两端进行抑制:
最后,还有一个小问题,这在上面的 gif 中无法体现,但当听音乐时会立即注意到:条跃动太早了,它们在你意料不到的时候跃动起来.
这种不同步的行为是因为在ExoPlayer AudioProcessor中,我们在数据传递到AudioTrack之前接收到数据,而AudioTrack有自己的缓冲区,这会导致视觉效果领先于音频效果,导致延迟输出.
对此的解决方案是将ExoPlayer缓冲区大小计算部分的代码进行复制,因此我的AudioProcessor中的缓冲区大小与AudioTrack完全相同.
我将传入的字节放在缓冲区的末尾,只处理缓冲区开头的字节(FIFO 队列),我如愿以偿延迟了 FFT.
我创建了一个代码仓库,这上面,我通过播放在线广播并使用我创建的可视化器进行绘图,以展示我的 FFT 处理器。它肯定不能直接用于线上产品,但如果您正在为音乐APP寻找可视化工具,它会提供一个很好的基础.
原文地址:https://juejin.cn/post/6996076172714967071最后此篇关于Android Visualizer 可视化器的自定义实现的文章就讲到这里了,如果你想了解更多关于Android Visualizer 可视化器的自定义实现的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
好的,所以我编辑了以下... 只需将以下内容放入我的 custom.css #rt-utility .rt-block {CODE HERE} 但是当我尝试改变... 与 #rt-sideslid
在表格 View 中,我有一个自定义单元格(在界面生成器中高度为 500)。在该单元格中,我有一个 Collection View ,我按 (10,10,10,10) 固定到边缘。但是在 tablev
对于我的无能,我很抱歉,但总的来说,我对 Cocoa、Swift 和面向对象编程还很陌生。我的主要来源是《Cocoa Programming for OS X》(第 5 版),以及 Apple 的充满
我正在使用 meta-tegra 为我的 NVIDIA Jetson Nano 构建自定义图像。我需要 PyTorch,但没有它的配方。我在设备上构建了 PyTorch,并将其打包到设备上的轮子中。现
在 jquery 中使用 $.POST 和 $.GET 时,有没有办法将自定义变量添加到 URL 并发送它们?我尝试了以下方法: $.ajax({type:"POST", url:"file.php?
Traefik 已经默认实现了很多中间件,可以满足大部分我们日常的需求,但是在实际工作中,用户仍然还是有自定义中间件的需求,为解决这个问题,官方推出了一个 Traefik Pilot[1] 的功
我想让我的 CustomTextInputLayout 将 Widget.MaterialComponents.TextInputLayout.OutlinedBox 作为默认样式,无需在 XML 中
我在 ~/.emacs 中有以下自定义函数: (defun xi-rgrep (term) (grep-compute-defaults) (interactive "sSearch Te
我有下表: 考虑到每个月的权重,我的目标是在 5 个月内分散 10,000 个单位。与 10,000 相邻的行是我最好的尝试(我在这上面花了几个小时)。黄色是我所追求的。 我试图用来计算的逻辑如下:计
我的表单中有一个字段,它是文件类型。当用户点击保存图标时,我想自然地将文件上传到服务器并将文件名保存在数据库中。我尝试通过回显文件名来测试它,但它似乎不起作用。另外,如何将文件名添加到数据库中?是在模
我有一个 python 脚本来发送电子邮件,它工作得很好,但问题是当我检查我的电子邮件收件箱时。 我希望该用户名是自定义用户名,而不是整个电子邮件地址。 最佳答案 发件人地址应该使用的格式是: You
我想减小 ggcorrplot 中标记的大小,并减少文本和绘图之间的空间。 library(ggcorrplot) data(mtcars) corr <- round(cor(mtcars), 1)
GTK+ noob 问题在这里: 是否可以自定义 GtkFileChooserButton 或 GtkFileChooserDialog 以删除“位置”部分(左侧)和顶部的“位置”输入框? 我实际上要
我正在尝试在主页上使用 ajax 在 magento 中使用 ajax 显示流行的产品列表,我可以为 5 或“N”个产品执行此操作,但我想要的是将分页工具栏与结果集一起添加. 这是我添加的以显示流行产
我正在尝试使用 PasswordResetForm 内置函数。 由于我想要自定义表单字段,因此我编写了自己的表单: class FpasswordForm(PasswordResetForm):
据我了解,新的 Angular 7 提供了拖放功能。我搜索了有关 DnD 的 Tree 组件,但没有找到与树相关的内容。 我在 Stackblitz 上找到的一个工作示例.对比drag'ndrop功能
我必须开发一个自定义选项卡控件并决定使用 WPF/XAML 创建它,因为我无论如何都打算学习它。完成后应该是这样的: 到目前为止,我取得了很好的进展,但还有两个问题: 只有第一个/最后一个标签项应该有
我要定制xtable用于导出到 LaTeX。我知道有些问题是关于 xtable在这里,但我找不到我要找的具体东西。 以下是我的表的外观示例: my.table <- data.frame(Specif
用ejs在这里显示日期 它给我结果 Tue Feb 02 2016 16:02:24 GMT+0530 (IST) 但是我需要表现为 19th January, 2016 如何在ejs中执行此操作?
我想问在 JavaFX 中使用自定义对象制作 ListView 的最佳方法,我想要一个每个项目如下所示的列表: 我搜了一下,发现大部分人都是用细胞工厂的方法来做的。有没有其他办法?例如使用客户 fxm
我是一名优秀的程序员,十分优秀!