我想要得到的声音的某些频率范围的值,是由智能手机播放,这样我可以通过蓝牙将它们转发到一个设备,可视化这些范围。这些范围是:
0-63赫兹
63-160赫兹
160-400赫兹
400-1000赫兹
1000-2.500Hz
2.500-6.250Hz
6.250-16.000Hz
音频会话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发布于 2020-03-04 15:17:24
它是计算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
}我没有测试上面的任何一个,所以可能有错误。只是想传达策略。
https://stackoverflow.com/questions/60527292
复制相似问题