From 1a860caaefff00113d6a66e775086c749a47af27 Mon Sep 17 00:00:00 2001
From: mike
Date: Sat, 29 Oct 2016 10:20:23 +0200
Subject: [PATCH] FFT averages
Added functions for liner and logarithmic grouping of the frequency
spectrum and also a function for generating the octave bands dynamically
---
src/fft.js | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 116 insertions(+)
diff --git a/src/fft.js b/src/fft.js
index 3dee42a8..dad1d4cf 100644
--- a/src/fft.js
+++ b/src/fft.js
@@ -484,6 +484,122 @@ define(function (require) {
this.analyser = undefined;
}
+ /**
+ * Returns an array of average amplitude values for a given number
+ * of frequency bands split equally. N defaults to 16.
+ * NOTE: analyze() must be called prior to linAverages(). Analyze()
+ * tells the FFT to analyze frequency data, and linAverages() uses
+ * the results to group them into a smaller set of averages.
+ *
+ * @method linAverages
+ * @param {Number} N Number of returned frequency groups
+ * @return {Array} linearAverages Array of average amplitude values for each group
+ */
+ p5.FFT.prototype.linAverages = function(N) {
+ var N = N || 16; // This prevents undefined, null or 0 values of N
+
+ var spectrum = this.freqDomain;
+ var spectrumLength = spectrum.length;
+ var spectrumStep = Math.floor(spectrumLength / N);
+
+ var linearAverages = new Array(N);
+ // Keep a second index for the current average group and place the values accordingly
+ // with only one loop in the spectrum data
+ var groupIndex = 0;
+
+ for (var specIndex = 0; specIndex < spectrumLength; specIndex++) {
+
+ linearAverages[groupIndex] = (linearAverages[groupIndex] !== undefined)
+ ? (linearAverages[groupIndex] + spectrum[specIndex]) / 2
+ : spectrum[specIndex];
+
+ // Increase the group index when the last element of the group is processed
+ if ((specIndex % spectrumStep) == (spectrumStep - 1)) {
+ groupIndex++;
+ }
+ }
+
+ return (linearAverages);
+ }
+
+ /**
+ * Returns an array of average amplitude values of the spectrum, for a given
+ * set of
+ * Octave Bands
+ * NOTE: analyze() must be called prior to logAverages(). Analyze()
+ * tells the FFT to analyze frequency data, and logAverages() uses
+ * the results to group them into a smaller set of averages.
+ *
+ * @method logAverages
+ * @param {Array} octaveBands Array of Octave Bands objects for grouping
+ * @return {Array} logAverages Array of average amplitude values for each group
+ */
+ p5.FFT.prototype.logAverages = function(octaveBands) {
+ var nyquist = p5sound.audiocontext.sampleRate / 2;
+ var spectrum = this.freqDomain;
+ var spectrumLength = spectrum.length;
+
+ var logAverages = new Array(octaveBands.length);
+ // Keep a second index for the current average group and place the values accordingly
+ // With only one loop in the spectrum data
+ var octaveIndex = 0;
+
+ for (var specIndex = 0; specIndex < spectrumLength; specIndex++) {
+ var specIndexFrequency = Math.round((specIndex * nyquist) / this.freqDomain.length);
+
+ // Increase the group index if the current frequency exceeds the limits of the band
+ if (specIndexFrequency > octaveBands[octaveIndex].hi) {
+ octaveIndex++;
+ }
+
+ logAverages[octaveIndex] = (logAverages[octaveIndex] !== undefined)
+ ? (logAverages[octaveIndex] + spectrum[specIndex]) / 2
+ : spectrum[specIndex];
+ }
+
+ return (logAverages);
+ }
+
+ /**
+ * Calculates and Returns the 1/N
+ * Octave Bands
+ * N defaults to 3 and minimum central frequency to 15.625Hz.
+ * (1/3 Octave Bands ~= 31 Frequency Bands)
+ * Setting fCtr0 to a central value of a higher octave will ignore the lower bands
+ * and produce less frequency groups.
+ *
+ * @method getOctaveBands
+ * @param {Number} N Specifies the 1/N type of generated octave bands
+ * @param {Number} fCtr0 Minimum central frequency for the lowest band
+ * @return {Array} octaveBands Array of octave band objects with their bounds
+ */
+ p5.FFT.prototype.getOctaveBands = function(N, fCtr0) {
+ var N = N || 3; // Default to 1/3 Octave Bands
+ var fCtr0 = fCtr0 || 15.625; // Minimum central frequency, defaults to 15.625Hz
+
+ var octaveBands = [];
+ var lastFrequencyBand = {
+ lo: fCtr0 / Math.pow(2, 1 / (2*N)),
+ ctr: fCtr0,
+ hi: fCtr0 * Math.pow(2, 1 / (2*N)),
+ };
+ octaveBands.push(lastFrequencyBand);
+
+ var nyquist = p5sound.audiocontext.sampleRate / 2;
+ while (lastFrequencyBand.hi < nyquist) {
+
+ var newFrequencyBand = {};
+ newFrequencyBand.lo = lastFrequencyBand.hi,
+ newFrequencyBand.ctr = lastFrequencyBand.ctr * Math.pow(2, 1 / N),
+ newFrequencyBand.hi = newFrequencyBand.ctr * Math.pow(2, 1 / (2*N)),
+
+ octaveBands.push(newFrequencyBand);
+ lastFrequencyBand = newFrequencyBand;
+ }
+
+ return (octaveBands);
+ }
+
// helper methods to convert type from float (dB) to int (0-255)
var freqToFloat = function (fft) {
if (fft.freqDomain instanceof Float32Array === false) {