Skip to content

Commit 1a860ca

Browse files
committed
FFT averages
Added functions for liner and logarithmic grouping of the frequency spectrum and also a function for generating the octave bands dynamically
1 parent b1781bf commit 1a860ca

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

src/fft.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,122 @@ define(function (require) {
484484
this.analyser = undefined;
485485
}
486486

487+
/**
488+
* Returns an array of average amplitude values for a given number
489+
* of frequency bands split equally. N defaults to 16.
490+
* <em>NOTE: analyze() must be called prior to linAverages(). Analyze()
491+
* tells the FFT to analyze frequency data, and linAverages() uses
492+
* the results to group them into a smaller set of averages.</em></p>
493+
*
494+
* @method linAverages
495+
* @param {Number} N Number of returned frequency groups
496+
* @return {Array} linearAverages Array of average amplitude values for each group
497+
*/
498+
p5.FFT.prototype.linAverages = function(N) {
499+
var N = N || 16; // This prevents undefined, null or 0 values of N
500+
501+
var spectrum = this.freqDomain;
502+
var spectrumLength = spectrum.length;
503+
var spectrumStep = Math.floor(spectrumLength / N);
504+
505+
var linearAverages = new Array(N);
506+
// Keep a second index for the current average group and place the values accordingly
507+
// with only one loop in the spectrum data
508+
var groupIndex = 0;
509+
510+
for (var specIndex = 0; specIndex < spectrumLength; specIndex++) {
511+
512+
linearAverages[groupIndex] = (linearAverages[groupIndex] !== undefined)
513+
? (linearAverages[groupIndex] + spectrum[specIndex]) / 2
514+
: spectrum[specIndex];
515+
516+
// Increase the group index when the last element of the group is processed
517+
if ((specIndex % spectrumStep) == (spectrumStep - 1)) {
518+
groupIndex++;
519+
}
520+
}
521+
522+
return (linearAverages);
523+
}
524+
525+
/**
526+
* Returns an array of average amplitude values of the spectrum, for a given
527+
* set of <a href="https://en.wikipedia.org/wiki/Octave_band" target="_blank">
528+
* Octave Bands</a>
529+
* <em>NOTE: analyze() must be called prior to logAverages(). Analyze()
530+
* tells the FFT to analyze frequency data, and logAverages() uses
531+
* the results to group them into a smaller set of averages.</em></p>
532+
*
533+
* @method logAverages
534+
* @param {Array} octaveBands Array of Octave Bands objects for grouping
535+
* @return {Array} logAverages Array of average amplitude values for each group
536+
*/
537+
p5.FFT.prototype.logAverages = function(octaveBands) {
538+
var nyquist = p5sound.audiocontext.sampleRate / 2;
539+
var spectrum = this.freqDomain;
540+
var spectrumLength = spectrum.length;
541+
542+
var logAverages = new Array(octaveBands.length);
543+
// Keep a second index for the current average group and place the values accordingly
544+
// With only one loop in the spectrum data
545+
var octaveIndex = 0;
546+
547+
for (var specIndex = 0; specIndex < spectrumLength; specIndex++) {
548+
var specIndexFrequency = Math.round((specIndex * nyquist) / this.freqDomain.length);
549+
550+
// Increase the group index if the current frequency exceeds the limits of the band
551+
if (specIndexFrequency > octaveBands[octaveIndex].hi) {
552+
octaveIndex++;
553+
}
554+
555+
logAverages[octaveIndex] = (logAverages[octaveIndex] !== undefined)
556+
? (logAverages[octaveIndex] + spectrum[specIndex]) / 2
557+
: spectrum[specIndex];
558+
}
559+
560+
return (logAverages);
561+
}
562+
563+
/**
564+
* Calculates and Returns the 1/N
565+
* <a href="https://en.wikipedia.org/wiki/Octave_band" target="_blank">Octave Bands</a>
566+
* N defaults to 3 and minimum central frequency to 15.625Hz.
567+
* (1/3 Octave Bands ~= 31 Frequency Bands)
568+
* Setting fCtr0 to a central value of a higher octave will ignore the lower bands
569+
* and produce less frequency groups.
570+
*
571+
* @method getOctaveBands
572+
* @param {Number} N Specifies the 1/N type of generated octave bands
573+
* @param {Number} fCtr0 Minimum central frequency for the lowest band
574+
* @return {Array} octaveBands Array of octave band objects with their bounds
575+
*/
576+
p5.FFT.prototype.getOctaveBands = function(N, fCtr0) {
577+
var N = N || 3; // Default to 1/3 Octave Bands
578+
var fCtr0 = fCtr0 || 15.625; // Minimum central frequency, defaults to 15.625Hz
579+
580+
var octaveBands = [];
581+
var lastFrequencyBand = {
582+
lo: fCtr0 / Math.pow(2, 1 / (2*N)),
583+
ctr: fCtr0,
584+
hi: fCtr0 * Math.pow(2, 1 / (2*N)),
585+
};
586+
octaveBands.push(lastFrequencyBand);
587+
588+
var nyquist = p5sound.audiocontext.sampleRate / 2;
589+
while (lastFrequencyBand.hi < nyquist) {
590+
591+
var newFrequencyBand = {};
592+
newFrequencyBand.lo = lastFrequencyBand.hi,
593+
newFrequencyBand.ctr = lastFrequencyBand.ctr * Math.pow(2, 1 / N),
594+
newFrequencyBand.hi = newFrequencyBand.ctr * Math.pow(2, 1 / (2*N)),
595+
596+
octaveBands.push(newFrequencyBand);
597+
lastFrequencyBand = newFrequencyBand;
598+
}
599+
600+
return (octaveBands);
601+
}
602+
487603
// helper methods to convert type from float (dB) to int (0-255)
488604
var freqToFloat = function (fft) {
489605
if (fft.freqDomain instanceof Float32Array === false) {

0 commit comments

Comments
 (0)