FFT produces complex numbers, where each number reflects frequency domain information about a bucket containing a continuous range frequencies. The usual approach for interpreting FFT data is as follows:

first determine the frequency bucket size by dividing the length of the FFT table by the sampling rate, let's call it `bucketSize`

;

then each bucket with index `i`

(assuming it's 0-based) contains information about frequencies in the range from `i * bucketSize`

to `(i + 1) * bucketSize`

Hz;

for real-valued signals, the values of the second half of the FFT table (for buckets of frequencies above `samplingRate / 2`

) will be just a mirror of the first half, so they are usually discarded;

to find the magnitude (signal level) for the frequencies in the bucket, one needs to take the complex value from the FFT table for this bucket, say it's `a + ib`

, and calculate `sqrt(a*a + b*b)`

.

Now back to the results of `onFftDataCapture`

. Here the `fft`

array contains complex numbers as consecutive pairs of bytes, so `fft[0]`

and `fft[1]`

comprise the complex number for the first bucket, `fft[2]`

and `fft[3]`

-- for the second, and so on.

Because, as I've mentioned, for real-valued signals the second part of the FFT table doesn't bring any benefit, it's **not** provided in the `fft`

array. But since each FFT bucket takes two array cells, the bucket size in Hz will still be calculated as `fft.length / samplingRate`

. Note that `fft.length`

is actually the capture size set by `setCaptureSize`

method of the Visualizer.

The magnitude of the bucket of frequencies can be easily calculated using `Math.hypot`

function, e.g. for the first bucket it's `Math.hypot(fft[0], fft[1])`

.