diff --git a/source/ABotVis.hx b/source/ABotVis.hx index 279c5918d..48b327077 100644 --- a/source/ABotVis.hx +++ b/source/ABotVis.hx @@ -82,7 +82,7 @@ class ABotVis extends FlxTypedSpriteGroup fftSamples.push(balanced); } - var freqShit = funnyFFT(fftSamples); + var freqShit = vis.funnyFFT(fftSamples); for (i in 0...group.members.length) { @@ -150,89 +150,4 @@ class ABotVis extends FlxTypedSpriteGroup } } } - - function funnyFFT(samples:Array, ?skipped:Int = 1):Array> - { - // 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> = []; - - 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; - } } diff --git a/source/SpectogramSprite.hx b/source/SpectogramSprite.hx index 0f8921528..7f5509d74 100644 --- a/source/SpectogramSprite.hx +++ b/source/SpectogramSprite.hx @@ -193,7 +193,7 @@ class SpectogramSprite extends FlxTypedSpriteGroup fftSamples.push(balanced); } - var freqShit = funnyFFT(fftSamples); + var freqShit = vis.funnyFFT(fftSamples); for (i in 0...group.members.length) { @@ -281,85 +281,6 @@ class SpectogramSprite extends FlxTypedSpriteGroup } } } - - function funnyFFT(samples:Array, ?skipped:Int = 1):Array> - { - // 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> = []; - - 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 diff --git a/source/VisShit.hx b/source/VisShit.hx index b0d4ef3aa..29ecf197b 100644 --- a/source/VisShit.hx +++ b/source/VisShit.hx @@ -1,8 +1,12 @@ package; +import dsp.FFT; +import flixel.math.FlxMath; import flixel.system.FlxSound; import lime.utils.Int16Array; +using Lambda; + class VisShit { public var snd:FlxSound; @@ -16,6 +20,91 @@ class VisShit this.snd = snd; } + public function funnyFFT(samples:Array, ?skipped:Int = 1):Array> + { + // 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> = []; + + 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() { if (snd != null && snd.playing)