made fft stuff less copypastiues

This commit is contained in:
Cameron Taylor 2021-10-07 21:06:45 -04:00
parent 09bb68f7ad
commit 33ed47bbf5
3 changed files with 91 additions and 166 deletions

View file

@ -82,7 +82,7 @@ class ABotVis extends FlxTypedSpriteGroup<FlxSprite>
fftSamples.push(balanced); fftSamples.push(balanced);
} }
var freqShit = funnyFFT(fftSamples); var freqShit = vis.funnyFFT(fftSamples);
for (i in 0...group.members.length) for (i in 0...group.members.length)
{ {
@ -150,89 +150,4 @@ class ABotVis extends FlxTypedSpriteGroup<FlxSprite>
} }
} }
} }
function funnyFFT(samples:Array<Float>, ?skipped:Int = 1):Array<Array<Float>>
{
// nab multiple samples at once in while / for loops?
var fs:Float = 44100 / skipped; // sample rate shit?
final fftN = 1024;
final halfN = Std.int(fftN / 2);
final overlap = 0.5;
final hop = Std.int(fftN * (1 - overlap));
// window function to compensate for overlapping
final a0 = 0.5; // => Hann(ing) window
final window = (n:Int) -> a0 - (1 - a0) * Math.cos(2 * Math.PI * n / fftN);
// NOTE TO SELF FOR WHEN I WAKE UP
// helpers, note that spectrum indexes suppose non-negative frequencies
final binSize = fs / fftN;
final indexToFreq = function(k:Int)
{
var powShit:Float = FlxMath.remapToRange(k, 0, halfN, 0, 4.3); // 4.3 is almost 20khz
return 1.0 * (Math.pow(10, powShit)); // we need the `1.0` to avoid overflows
};
// "melodic" band-pass filter
final minFreq = 20.70;
final maxFreq = 4000.01;
final melodicBandPass = function(k:Int, s:Float)
{
// final freq = indexToFreq(k);
// final filter = freq > minFreq - binSize && freq < maxFreq + binSize ? 1 : 0;
return s;
};
var freqOutput:Array<Array<Float>> = [];
var c = 0; // index where each chunk begins
var indexOfArray:Int = 0;
while (c < samples.length)
{
// take a chunk (zero-padded if needed) and apply the window
final chunk = [
for (n in 0...fftN)
(c + n < samples.length ? samples[c + n] : 0.0) * window(n)
];
// compute positive spectrum with sampling correction and BP filter
final freqs = FFT.rfft(chunk).map(z -> z.scale(1 / fftN).magnitude).mapi(melodicBandPass);
freqOutput.push([]);
// if (FlxG.keys.justPressed.M)
// trace(FFT.rfft(chunk).map(z -> z.scale(1 / fs).magnitude));
// find spectral peaks and their instantaneous frequencies
for (k => s in freqs)
{
final time = c / fs;
final freq = indexToFreq(k);
final power = s * s;
if (FlxG.keys.justPressed.I)
{
trace(k);
haxe.Log.trace('${time};${freq};${power}', null);
}
if (freq < maxFreq)
freqOutput[indexOfArray].push(power);
//
}
// haxe.Log.trace("", null);
indexOfArray++;
// move to next (overlapping) chunk
c += hop;
}
if (FlxG.keys.justPressed.C)
trace(freqOutput.length);
return freqOutput;
}
} }

View file

@ -193,7 +193,7 @@ class SpectogramSprite extends FlxTypedSpriteGroup<FlxSprite>
fftSamples.push(balanced); fftSamples.push(balanced);
} }
var freqShit = funnyFFT(fftSamples); var freqShit = vis.funnyFFT(fftSamples);
for (i in 0...group.members.length) for (i in 0...group.members.length)
{ {
@ -281,85 +281,6 @@ class SpectogramSprite extends FlxTypedSpriteGroup<FlxSprite>
} }
} }
} }
function funnyFFT(samples:Array<Float>, ?skipped:Int = 1):Array<Array<Float>>
{
// nab multiple samples at once in while / for loops?
var fs:Float = 44100 / skipped; // sample rate shit?
final fftN = 1024;
final halfN = Std.int(fftN / 2);
final overlap = 0.5;
final hop = Std.int(fftN * (1 - overlap));
// window function to compensate for overlapping
final a0 = 0.5; // => Hann(ing) window
final window = (n:Int) -> a0 - (1 - a0) * Math.cos(2 * Math.PI * n / fftN);
// helpers, note that spectrum indexes suppose non-negative frequencies
final binSize = fs / fftN;
final indexToFreq = function(k:Int)
{
var powShit:Float = FlxMath.remapToRange(k, 0, halfN, 0, 4.3); // 4.3 is almost 20khz
return 1.0 * (Math.pow(10, powShit)); // we need the `1.0` to avoid overflows
};
// "melodic" band-pass filter
final minFreq = 20.70;
final maxFreq = 4000.01;
final melodicBandPass = function(k:Int, s:Float)
{
// final freq = indexToFreq(k);
// final filter = freq > minFreq - binSize && freq < maxFreq + binSize ? 1 : 0;
return s;
};
var freqOutput:Array<Array<Float>> = [];
var c = 0; // index where each chunk begins
var indexOfArray:Int = 0;
while (c < samples.length)
{
// take a chunk (zero-padded if needed) and apply the window
final chunk = [
for (n in 0...fftN)
(c + n < samples.length ? samples[c + n] : 0.0) * window(n)
];
// compute positive spectrum with sampling correction and BP filter
final freqs = FFT.rfft(chunk).map(z -> z.scale(1 / fftN).magnitude).mapi(melodicBandPass);
freqOutput.push([]);
// find spectral peaks and their instantaneous frequencies
for (k => s in freqs)
{
final time = c / fs;
final freq = indexToFreq(k);
final power = s * s;
if (FlxG.keys.justPressed.N)
{
trace(k);
haxe.Log.trace('${time};${freq};${power}', null);
}
if (freq < maxFreq)
freqOutput[indexOfArray].push(power);
//
}
// haxe.Log.trace("", null);
indexOfArray++;
// move to next (overlapping) chunk
c += hop;
}
if (FlxG.keys.justPressed.C)
trace(freqOutput.length);
return freqOutput;
}
} }
enum VISTYPE enum VISTYPE

View file

@ -1,8 +1,12 @@
package; package;
import dsp.FFT;
import flixel.math.FlxMath;
import flixel.system.FlxSound; import flixel.system.FlxSound;
import lime.utils.Int16Array; import lime.utils.Int16Array;
using Lambda;
class VisShit class VisShit
{ {
public var snd:FlxSound; public var snd:FlxSound;
@ -16,6 +20,91 @@ class VisShit
this.snd = snd; this.snd = snd;
} }
public function funnyFFT(samples:Array<Float>, ?skipped:Int = 1):Array<Array<Float>>
{
// nab multiple samples at once in while / for loops?
var fs:Float = 44100 / skipped; // sample rate shit?
final fftN = 1024;
final halfN = Std.int(fftN / 2);
final overlap = 0.5;
final hop = Std.int(fftN * (1 - overlap));
// window function to compensate for overlapping
final a0 = 0.5; // => Hann(ing) window
final window = (n:Int) -> a0 - (1 - a0) * Math.cos(2 * Math.PI * n / fftN);
// NOTE TO SELF FOR WHEN I WAKE UP
// helpers, note that spectrum indexes suppose non-negative frequencies
final binSize = fs / fftN;
final indexToFreq = function(k:Int)
{
var powShit:Float = FlxMath.remapToRange(k, 0, halfN, 0, 4.3); // 4.3 is almost 20khz
return 1.0 * (Math.pow(10, powShit)); // we need the `1.0` to avoid overflows
};
// "melodic" band-pass filter
final minFreq = 20.70;
final maxFreq = 4000.01;
final melodicBandPass = function(k:Int, s:Float)
{
// final freq = indexToFreq(k);
// final filter = freq > minFreq - binSize && freq < maxFreq + binSize ? 1 : 0;
return s;
};
var freqOutput:Array<Array<Float>> = [];
var c = 0; // index where each chunk begins
var indexOfArray:Int = 0;
while (c < samples.length)
{
// take a chunk (zero-padded if needed) and apply the window
final chunk = [
for (n in 0...fftN)
(c + n < samples.length ? samples[c + n] : 0.0) * window(n)
];
// compute positive spectrum with sampling correction and BP filter
final freqs = FFT.rfft(chunk).map(z -> z.scale(1 / fftN).magnitude).mapi(melodicBandPass);
freqOutput.push([]);
// if (FlxG.keys.justPressed.M)
// trace(FFT.rfft(chunk).map(z -> z.scale(1 / fs).magnitude));
// find spectral peaks and their instantaneous frequencies
for (k => s in freqs)
{
final time = c / fs;
final freq = indexToFreq(k);
final power = s * s;
if (FlxG.keys.justPressed.I)
{
trace(k);
haxe.Log.trace('${time};${freq};${power}', null);
}
if (freq < maxFreq)
freqOutput[indexOfArray].push(power);
//
}
// haxe.Log.trace("", null);
indexOfArray++;
// move to next (overlapping) chunk
c += hop;
}
if (FlxG.keys.justPressed.C)
trace(freqOutput.length);
return freqOutput;
}
public function checkAndSetBuffer() public function checkAndSetBuffer()
{ {
if (snd != null && snd.playing) if (snd != null && snd.playing)