noise
noise copied to clipboard
Spectral analysis
Hello, This is not really an issue, but rather a question about how to use your library. We are trying to use your library to compute power spectral density on a live audio signal in an Android app. We want results per octave band, or per ⅓ octave band. Currently we have to following Kotlin code for the octave band version. We adapted this from the code that drives the bottom graph in your demo app.
package com.paramsen.noise
import kotlin.math.log10
class SoundSpectrumUtils {
companion object {
private const val bands = 11
private val lbands: Array<Int> = arrayOf(11, 22, 44, 88, 177, 355, 710, 1420, 2840, 5680, 11360);
private val ubands = arrayOf(22, 44, 88, 177, 355, 710, 1420, 2840, 5680, 11360, 22050);
private val bandSizes = IntArray(bands) { i -> ubands[i] - lbands[i] }
@JvmStatic
fun calculateBands(samples: FloatArray): FloatArray {
val noise = Noise.real(samples.size)
// not sure why this is, but it's in the sample app, see also https://github.com/paramsen/noise/issues/6
for (i in samples.indices) {
samples[i] *= 2.0f
}
val fft = noise.fft(samples, FloatArray(samples.size + 2))
val resultFFT = FloatArray(samples.size);
System.arraycopy(fft, 2, resultFFT, 0, fft.size - 2)
val resultBands = FloatArray(bands);
for (i in 0 until bands) {
var accum = .0f
for (j in 0 until bandSizes[i] step 2) {
//convert real and imag part to get energy
accum += (Math.pow(
resultFFT[j + lbands[i]].toDouble(),
2.0
) + Math.pow(resultFFT[j + 1 + lbands[i]].toDouble(), 2.0)).toFloat()
}
accum /= bandSizes[i] / 2
accum = 10 * log10(accum)
resultBands[i] = accum;
}
return resultBands;
}
}
}
We have following challenges with this:
- we're not sure why the sample values are doubled in the beginning. Is this even necessary?
- the resulting dB values are unrealistically high, so perhaps we are computing the dB wrong?
- we're not entirely sure how to adapt this code to work for ⅓ octave bands (https://www.engineeringtoolbox.com/octave-bands-frequency-limits-d_1602.html)
Thanks in advance for any pointers you might be able to give.
For acoustics, decibels are commonly reported relative to an SPL of 20 μPa corresponding to 0 dB. And if the decibels are being reported for comparison to human hearing, they are usually also A-weighted to account for how very high or low frequencies are not very audible to the human ear. Assuming your incoming samples
come from AudioRecord and are on a scale from 0 to 1, you would need to have some way of knowing what value corresponds with 20 μPa in order to perform this calculation. It would be microphone-hardware dependent. I haven't looked into whether Android provides some way to read microphone specs.