Files
Funkin/source/funkin/audio/visualize/ABotVis.hx
T
FuroandHundrec 6607645786 Fixed Memory Leaks on funkVis and grig.audio
The memory leak was due to not caching the audio levels and these libraries allocating arrays on every frame, it has been fixed in their each repository through a pull request.
2025-10-02 03:20:12 +08:00

153 lines
4.1 KiB
Haxe

package funkin.audio.visualize;
import funkin.graphics.FunkinSprite;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
import flixel.sound.FlxSound;
import funkin.vis.dsp.SpectralAnalyzer;
using Lambda;
@:nullSafety
class ABotVis extends FlxTypedSpriteGroup<FlxSprite>
{
// public var vis:VisShit;
var analyzer:Null<SpectralAnalyzer> = null;
var analyzerLevelsCache:Array<Bar> = new Array<Bar>();
var volumes:Array<Float> = [];
public var snd:Null<FlxSound> = null;
static final BAR_COUNT:Int = 7;
// TODO: Make the sprites easier to soft code.
public function new(snd:FlxSound, pixel:Bool)
{
super();
this.snd = snd;
var visCount = pixel ? (BAR_COUNT + 1) : (BAR_COUNT + 1);
var visScale = pixel ? 6 : 1;
var visFrms:FlxAtlasFrames = Paths.getSparrowAtlas(pixel ? 'characters/abotPixel/aBotVizPixel' : 'characters/abot/aBotViz');
// these are the differences in X position, from left to right
var positionX:Array<Float> = pixel ? [0, 7 * 6, 8 * 6, 9 * 6, 10 * 6, 6 * 6, 7 * 6] : [0, 59, 56, 66, 54, 52, 51];
var positionY:Array<Float> = pixel ? [0, -2 * 6, -1 * 6, 0, 0, 1 * 6, 2 * 6] : [0, -8, -3.5, -0.4, 0.5, 4.7, 7];
for (index in 1...visCount)
{
// pushes initial value
volumes.push(0.0);
// Sum the offsets up to the current index
var sum = function(num:Float, total:Float) return total += num;
var posX:Float = positionX.slice(0, index).fold(sum, 0);
var posY:Float = positionY.slice(0, index).fold(sum, 0);
var viz:FunkinSprite = new FunkinSprite(posX, posY);
viz.frames = visFrms;
viz.antialiasing = pixel ? false : true;
viz.scale.set(visScale, visScale);
add(viz);
var visStr = 'viz';
viz.animation.addByPrefix('VIZ', '$visStr${index}0', 0);
viz.animation.play('VIZ', false, false, 1);
}
}
public function initAnalyzer():Void
{
if (snd == null) return;
@:privateAccess
analyzer = new SpectralAnalyzer(snd._channel.__audioSource, BAR_COUNT, 0.1, 40);
// A-Bot tuning...
analyzer.minDb = -65;
analyzer.maxDb = -25;
analyzer.maxFreq = 22000;
// we use a very low minFreq since some songs use low low subbass like a boss
analyzer.minFreq = 10;
#if sys
// On native it uses FFT stuff that isn't as optimized as the direct browser stuff we use on HTML5
// So we want to manually change it!
analyzer.fftN = 256;
#end
// analyzer.maxDb = -35;
// analyzer.fftN = 2048;
}
public function dumpSound():Void
{
snd = null;
analyzer = null;
}
var visTimer:Float = -1;
var visTimeMax:Float = 1 / 30;
override function update(elapsed:Float)
{
super.update(elapsed);
}
static inline function min(x:Int, y:Int):Int
{
return x > y ? y : x;
}
override function draw()
{
super.draw();
drawFFT();
}
/**
* TJW funkin.vis based visualizer! updateFFT() is the old nasty shit that dont worky!
*/
function drawFFT():Void
{
analyzerLevelsCache = (analyzer != null) ? analyzer.getLevels(analyzerLevelsCache) : getDefaultLevels();
for (i in 0...min(group.members.length, analyzerLevelsCache.length))
{
var animFrame:Int = (FlxG.sound.volume == 0 || FlxG.sound.muted) ? 0 : Math.round(analyzerLevelsCache[i].value * 6);
// don't display if we're at 0 volume from the level
group.members[i].visible = animFrame > 0;
// decrement our animFrame, so we can get a value from 0-5 for animation frames
animFrame -= 1;
animFrame = Math.floor(Math.min(5, animFrame));
animFrame = Math.floor(Math.max(0, animFrame));
animFrame = Std.int(Math.abs(animFrame - 5)); // shitty dumbass flip, cuz dave got da shit backwards lol!
group.members[i].animation.curAnim.curFrame = animFrame;
}
}
/**
* Explicitly define the default levels to draw when the analyzer is not available.
* @return Array<Bar>
*/
static function getDefaultLevels():Array<Bar>
{
var result:Array<Bar> = [];
for (i in 0...BAR_COUNT)
{
result.push({value: 0, peak: 0.0});
}
return result;
}
}