Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spectral analysis #7

Open
mstevens83 opened this issue Aug 17, 2020 · 1 comment
Open

Spectral analysis #7

mstevens83 opened this issue Aug 17, 2020 · 1 comment

Comments

@mstevens83
Copy link

mstevens83 commented Aug 17, 2020

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:

Thanks in advance for any pointers you might be able to give.

@cypherdare
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants