使用 androids 可视化器类获取可变频率范围

2024-01-26

我想获取智能手机播放的声音的某些频率范围的值,以便我可以通过蓝牙将它们转发到可视化这些范围的设备。这些范围是:
0-63Hz
63-160赫兹
160-400赫兹
400-1000赫兹
1000-2.500Hz
2.500-6.250Hz
6.250-16.000赫兹

音频会话 ID 为 0,因此我可以使用智能手机播放的任何声音。

我发现的是可视化器类,我认为我可以使用 getFft 方法来实现它。虽然看起来我只能将频率分成与捕获率相同大小的部分?或者我完全误解了这里的某些东西?我尝试仅使用采样率作为捕获率,这样我就会为每个频率提供一个值,但它只会再次将捕获率设置为 1024。
或者也许这门课不是我想要的? 我想我可能完全错过了这里的要点,所以任何帮助或解释(或另一个图书馆的推荐)将受到欢迎。

        val visualizer = Visualizer(0)
        visualizer.scalingMode = 0

        visualizer.setDataCaptureListener(object : Visualizer.OnDataCaptureListener {
            override fun onWaveFormDataCapture(
                vis: Visualizer,
                bytes: ByteArray,
                samplingRate: Int
            ) {

            }

            override fun onFftDataCapture(
                visualizer: Visualizer?,
                fft: ByteArray?,
                samplingRate: Int
            ) {
                //if frequency <=63 do something
                //else if frequency <=160 do something ...
            }

        }, Visualizer.getMaxCaptureRate() / 2, false, true)
        visualizer.enabled = true



FFT 计算的数学原理是,它将产生大小均匀、计数等于样本大小一半的频率“桶”,并上升到采样率一半的频率。 (FFT 实际上会生成等于样本大小的存储桶,但 Android 的 Visualizer 会在提供结果之前转储后半部分,因为它们包含前半部分的反射,因此对于可视化没有用处。)

根据硬件功能和普通的旧物理原理,允许的捕获大小和捕获率的范围将非常有限。而且,这两个属性成反比。如果您的捕获尺寸很大,那么您的捕获率就必须很小。音频以均匀定时的幅度流的形式产生(其中间隔是samplingRate)。为简单起见,假设音频流仅为 1024 Hz,每秒产生 1024 个幅度。如果您的捕获速率为每秒 1 个,则每次捕获时您将收集所有 1024 个幅度,因此您的捕获大小为 1024。如果您的捕获速率为每秒 2 个,则每次捕获时您将收集 512 个幅度,因此您的捕获尺寸是512。

请注意,我不确定您是否设置了捕获大小,并且它与您使用的捕获率不成反比setDataCaptureListener,它是否忽略您设置的大小或实际重复/删除数据。我总是用Visualizer.getMaxCaptureRate()作为捕获率。

您可以做的(并且不会准确)是对适当的范围进行平均,尽管我认为您需要在平均之前将对数函数应用于幅度,否则结果看起来不会很好。在将它们可视化之前,您肯定需要在某个时刻对幅度应用对数函数,以便可视化工具对查看者有意义。

因此,选择捕获大小后,您可以准备用于收集结果的范围。

private val targetEndpoints = listOf(0f, 63f, 160f, 400f, 1000f, 2500f, 6250f, 16000f)
private val DESIRED_CAPTURE_SIZE = 1024 // A typical value, has worked well for me
private lateinit var frequencyOrdinalRanges: List<IntRange>
//...

val captureSizeRange = Visualizer.getCaptureSizeRange().let { it[0]..it[1] }
val captureSize = DESIRED_CAPTURE_SIZE.coerceIn(captureSizeRange)
visualizer.captureSize = captureSize
val samplingRate = visualizer.samplingRate
frequencyOrdinalRanges = targetEndpoints.zipWithNext { a, b ->
        val startOrdinal = 1 + (captureSize * a / samplingRate).toInt()
        // The + 1 omits the DC offset in the first range, and the overlap for remaining ranges
        val endOrdinal = (captureSize * b / samplingRate).toInt()
        startOrdinal..endOrdinal
    }

然后在你的听众中

override fun onFftDataCapture(
    visualizer: Visualizer,
    fft: ByteArray,
    samplingRate: Int
) {
    val output = FloatArray(frequencyOrdinalRanges.size)
    for ((frequencyOrdinalRange, i) in frequencyOrdinalRanges.withIndex) {
        var logMagnitudeSum = 0f
        for (k in ordinalRange) {
            val fftIndex = k * 2
            logMagnitudeSum += log10(hypot(fft[fftIndex].toFloat(), fft[fftIndex + 1].toFloat()))
        }
        output[i] = logMagnitudeSum / (ordinalRange.last - ordinalRange.first + 1)
    }
    // If you want magnitude to be on a 0..1 scale, you can divide it by log10(hypot(127f, 127f))
    // Do something with output
}

以上我都没有测试过,所以可能会有错误。只是想传达策略。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 androids 可视化器类获取可变频率范围 的相关文章

  • 使用 GoogleServices 插件时忽略 Gradle ArchivesBaseName

    我经常使用 archivesbasename 来重命名我的输出 apk 但自从使用 google services 插件后 它就被忽略了 我能做些什么来让它再次工作吗 下面附上了我完整的 build gradle 感谢您的指点 apply
  • OPENGL ES 不工作:无当前上下文

    我尝试了 OpenGL ES2 for Android 一书中所示的程序 但它不起作用 我已经在Odroid E 三星s3 三星y 三星star上进行了测试 the gl version suported returns 2 but i g
  • 毕加索磁盘缓存

    我正在使用 Picasso 从 URL 加载图像 Picasso with getApplicationContext load product getImageUrl into imageView 据我所知 每次都会访问该网址 而不是缓存
  • FLAG_ACTIVITY_REORDER_TO_FRONT 被忽略

    我有一个包含项目列表的 FragmentActivity 当应用程序处于后台时 可以推送该项目列表 发生这种情况时 我想创建一个状态栏通知并提醒用户更新 当用户单击通知时 活动应重新排序到前面并显示在屏幕上 同时在列表底部显示新项目 所以我
  • 无法在云控制台中启用 Maps SDK for Android

    我在云控制台中启用适用于 Android 的 Maps SDK 时遇到此问题 https console cloud google com https console cloud google com 它会抛出以下错误 附截图 我收到错误消
  • 使用 mupdf android 库导航到特定页面

    我如何使用 muPDF 库导航到特定页面 或者有没有办法让图书馆不记得我最后在那个pdf文件中浏览的是哪一页 Uri uri Uri parse path Intent intent new Intent MainActivity getC
  • 如何在android中画一条曲线?

    我是 Android 新手 正在开发一个关于绘制线条的示例项目 我想画一条连接两点的曲线或高架线 x1 y1 and x2 y2 我试过canvas drawArc 方法 但是RectF内的值drawArc方法只是圆的 x y 中心点 它在
  • 如何在Android网格视图中设置单元格大小?

    我正在尝试为应用程序制作一个带有大图标的网格视图 但我找不到任何有关修改 Android 上网格布局上的单元格大小的教程 有人可以给我一个例子或相关链接吗 Thanks 就像另一个一样适配器视图 http developer android
  • Android Drawable 绘图性能?

    在我看来 我有一个简单的 ARGB 可绘制对象 大约需要 2 毫秒才能绘制 但我可以在 0 5 毫秒内绘制与位图相同的文件 只是一些快速代码 我真的不能认为它是一个选项 优化可绘制对象的绘制速度的最佳方法是什么 这取决于可绘制的数量以及每个
  • 按名称获取 ArrayList

    这是正确的获取方式吗ArrayList
  • 有没有办法在多个嵌套的 RecyclerView 之间共享同一个 LayoutManager

    我正在开发一个显示游戏列表的应用程序 在每个游戏的 itemView 内 我还有一个要显示的视频列表 预览和结构如下 我部署了一个RecyclerView作为窗口根视图 然后对于视频 我使用网格样式的RecyclerView来显示 所以这里
  • 无法登录 Google Play 游戏服务

    我在开发者控制台上使用包名称和正确的签名证书设置了我的游戏 并为其创建了排行榜 但没有创建任何成就 然后 我从以下位置下载了示例 Type A Number Challenge 和 BaseGameUtils https developer
  • BitmapFactory.decodeResource() 忽略 jpg 图像的 inPreferredConfig 选项

    我尝试将jpeg资源图像加载到ARGB 8888格式的位图 BitmapFactory Options opts new BitmapFactory Options opts inPreferredConfig Bitmap Config
  • 如何在 kotlin 中检查 lambda 空值

    在 Kotlin 中如何检查 lambda 是否为空 例如 我有这样的签名 onError Throwable gt Unit 我如何区分它的默认值是应用于主体还是应用于此函数的值 您无法测试 lambda 的主体是否为空 因此它不包含源代
  • SDK尚未初始化,请务必先调用FacebookSdk.sdkInitialize()

    我在实现 Facebook SDK 时遇到此错误 并且我tried https stackoverflow com questions 15490399 error inflating class com facebook widget l
  • 在片段之间切换时底部导航栏会向下推

    在我的活动中 我有一个底部导航栏和框架布局来显示片段 一切正常 但问题是当我开始按顺序从 1 4 移动时 底部导航栏保持在其位置 但当我突然从 4 跳到2 然后底部导航栏就会超出屏幕 当再次单击同一项目时 它就会回到正常位置 该视频将清楚地
  • 如何在 onDraw() 方法中定义与像素无关的高度

    我扩展了 View 来构建自定义小部件 我想用独立的像素单位定义小部件的高度 我认为可以通过将像素密度乘以所需的高度来完成 但我不知道该怎么做 到目前为止我所拥有的 最小化 public class Timeline extends Vie
  • 如何从灰度字节缓冲区图像创建位图?

    我正在尝试使用新的 Android 人脸检测移动视觉 API 来处理帧图像 所以我创建了自定义检测器来获取帧并尝试调用 getBitmap 方法 但它为空 所以我访问了帧的灰度数据 有没有办法从它或类似的图像持有者类创建位图 public
  • 尝试在空对象引用上调用虚拟方法 -> 解析?

    我尝试使用一个按钮从一个主要活动切换到另一个活动 但是当我尝试运行该应用程序时 它在单击该应用程序后立即自行关闭 我在命令中发现错误消息 Unable to start activity ComponentInfo fr amseu mys
  • 如何检查设备上是否安装了文本转语音 (TTS) 的特定语言数据?

    我正在创建一个使用文本转语音的应用程序 我希望用户能够离线使用它 因此我检查设备上是否安装了 TTS 数据 以下是执行此操作的代码 Check tts data is installed Intent checkTTSIntent new

随机推荐