Funkin/source/funkin/ui/debug/latency/LatencyState.hx

395 lines
12 KiB
Haxe
Raw Normal View History

package funkin.ui.debug.latency;
2020-10-06 21:56:14 -04:00
import funkin.data.notestyle.NoteStyleRegistry;
2020-10-06 21:56:14 -04:00
import flixel.FlxSprite;
2022-07-05 14:24:02 -04:00
import flixel.FlxSubState;
2022-07-06 15:27:45 -04:00
import flixel.group.FlxGroup;
2023-06-22 01:41:01 -04:00
import flixel.group.FlxGroup.FlxTypedGroup;
2022-07-06 15:27:45 -04:00
import flixel.math.FlxMath;
import funkin.ui.MusicBeatSubState;
import flixel.sound.FlxSound;
2020-10-06 21:56:14 -04:00
import flixel.text.FlxText;
2022-07-05 14:34:08 -04:00
import flixel.util.FlxColor;
import funkin.audio.visualize.PolygonSpectogram;
2023-06-22 01:41:01 -04:00
import funkin.play.notes.NoteSprite;
import funkin.ui.debug.latency.CoolStatsGraph;
2022-07-06 20:37:35 -04:00
import openfl.events.KeyboardEvent;
2024-01-09 13:16:00 -05:00
import funkin.input.PreciseInputManager;
import funkin.play.notes.Strumline;
import funkin.play.notes.notestyle.NoteStyle;
import funkin.data.notestyle.NoteStyleData;
import funkin.data.notestyle.NoteStyleRegistry;
2024-01-16 05:37:06 -05:00
import funkin.data.song.SongData.SongNoteData;
import haxe.Timer;
2024-02-12 20:06:43 -05:00
import flixel.FlxCamera;
2020-10-06 21:56:14 -04:00
2023-06-09 15:44:29 -04:00
class LatencyState extends MusicBeatSubState
2020-10-06 21:56:14 -04:00
{
2024-02-10 15:42:29 -05:00
var visualOffsetText:FlxText;
var offsetText:FlxText;
2024-04-04 19:46:08 -04:00
var noteGrp:Array<SongNoteData> = [];
2024-01-09 13:16:00 -05:00
var strumLine:Strumline;
2020-10-06 21:56:14 -04:00
var blocks:FlxTypedGroup<FlxSprite>;
2022-07-06 15:27:45 -04:00
var songPosVis:FlxSprite;
var songVisFollowVideo:FlxSprite;
var songVisFollowAudio:FlxSprite;
2022-07-06 15:27:45 -04:00
var beatTrail:FlxSprite;
var diffGrp:FlxTypedGroup<FlxText>;
2024-02-14 08:29:38 -05:00
var offsetsPerBeat:Array<Null<Int>> = [];
2024-04-04 19:46:08 -04:00
var swagSong:HomemadeMusic;
2024-02-12 20:06:43 -05:00
var previousVolume:Float;
var stateCamera:FlxCamera;
2022-07-12 19:02:38 -04:00
/**
* A local conductor instance for this testing class, in-case we are in a PlayState
* because I'm too lazy to set the old variables for conductor stuff !
*/
var localConductor:Conductor;
// stores values of what the previous persistent draw/update stuff was, example if opened
// from pause menu, we want to NOT draw persistently, but then resume drawing once closed
var prevPersistentDraw:Bool;
var prevPersistentUpdate:Bool;
override function create()
{
2023-12-12 23:28:16 -05:00
super.create();
prevPersistentDraw = FlxG.state.persistentDraw;
prevPersistentUpdate = FlxG.state.persistentUpdate;
FlxG.state.persistentDraw = false;
FlxG.state.persistentUpdate = false;
localConductor = new Conductor();
2024-02-12 22:44:59 -05:00
conductorInUse = localConductor;
2024-02-12 20:06:43 -05:00
stateCamera = new FlxCamera(0, 0, FlxG.width, FlxG.height);
stateCamera.bgColor = FlxColor.BLACK;
FlxG.cameras.add(stateCamera);
2023-12-12 23:28:16 -05:00
2024-02-12 20:06:43 -05:00
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK);
add(bg);
2022-07-12 19:02:38 -04:00
2024-02-12 20:06:43 -05:00
if (FlxG.sound.music != null)
{
previousVolume = FlxG.sound.music.volume;
FlxG.sound.music.volume = 0; // only want to mute the volume, incase we are coming from pause menu
}
else
previousVolume = 1; // defaults to 1 if no music is playing 🤔 also fuck it, emoji in code comment
2022-07-06 15:27:45 -04:00
2024-04-04 19:46:08 -04:00
swagSong = new HomemadeMusic();
2024-02-12 20:06:43 -05:00
swagSong.loadEmbedded(Paths.sound('soundTest'), true);
swagSong.looped = true;
swagSong.play();
FlxG.sound.list.add(swagSong);
2024-02-12 20:06:43 -05:00
PreciseInputManager.instance.onInputPressed.add(preciseInputPressed);
PreciseInputManager.instance.onInputReleased.add(preciseInputReleased);
localConductor.forceBPM(60);
FlxG.stage.addEventListener(KeyboardEvent.KEY_DOWN, key -> {
trace(key.charCode);
2024-04-04 19:46:08 -04:00
// if (key.charCode == 120) generateBeatStuff();
trace("\tEVENT PRESS: \t" + FlxG.sound.music.time + " " + Timer.stamp());
// trace(FlxG.sound.music.prevTimestamp);
trace(FlxG.sound.music.time);
trace("\tFR FR PRESS: \t" + swagSong.getTimeWithDiff());
// trace("\tREDDIT: \t" + swagSong.frfrTime + " " + Timer.stamp());
@:privateAccess
trace("\tREDDIT: \t" + FlxG.sound.music._channel.position + " " + Timer.stamp());
// trace("EVENT LISTENER: " + key);
});
// funnyStatsGraph.hi
Conductor.instance.forceBPM(60);
diffGrp = new FlxTypedGroup<FlxText>();
add(diffGrp);
for (beat in 0...Math.floor(swagSong.length / (localConductor.stepLengthMs * 2)))
{
var beatTick:FlxSprite = new FlxSprite(songPosToX(beat * (localConductor.stepLengthMs * 2)), FlxG.height - 15);
beatTick.makeGraphic(2, 15);
beatTick.alpha = 0.3;
add(beatTick);
2024-02-19 20:56:57 -05:00
var offsetTxt:FlxText = new FlxText(songPosToX(beat * (localConductor.stepLengthMs * 2)), FlxG.height - 26, 0, "");
offsetTxt.alpha = 0.5;
diffGrp.add(offsetTxt);
2024-02-14 08:29:38 -05:00
offsetsPerBeat.push(null);
}
songVisFollowAudio = new FlxSprite(0, FlxG.height - 20).makeGraphic(2, 20, FlxColor.YELLOW);
add(songVisFollowAudio);
songVisFollowVideo = new FlxSprite(0, FlxG.height - 20).makeGraphic(2, 20, FlxColor.BLUE);
add(songVisFollowVideo);
songPosVis = new FlxSprite(0, FlxG.height - 20).makeGraphic(2, 20, FlxColor.RED);
add(songPosVis);
beatTrail = new FlxSprite(0, songPosVis.y).makeGraphic(2, 20, FlxColor.PURPLE);
beatTrail.alpha = 0.7;
add(beatTrail);
blocks = new FlxTypedGroup<FlxSprite>();
add(blocks);
for (i in 0...8)
{
2024-02-10 15:42:29 -05:00
var block = new FlxSprite(2, ((FlxG.height / 8) + 2) * i).makeGraphic(Std.int(FlxG.height / 8), Std.int((FlxG.height / 8) - 4));
block.alpha = 0.1;
blocks.add(block);
}
2024-02-10 15:42:29 -05:00
var strumlineBG:FlxSprite = new FlxSprite();
add(strumlineBG);
2024-01-09 13:16:00 -05:00
strumLine = new Strumline(NoteStyleRegistry.instance.fetchDefault(), true);
strumLine.conductorInUse = localConductor;
2024-02-10 15:42:29 -05:00
strumLine.screenCenter();
add(strumLine);
2024-01-16 05:37:06 -05:00
2024-02-10 15:42:29 -05:00
strumlineBG.x = strumLine.x;
strumlineBG.makeGraphic(Std.int(strumLine.width), FlxG.height, 0xFFFFFFFF);
strumlineBG.alpha = 0.1;
visualOffsetText = new FlxText();
visualOffsetText.setFormat(Paths.font("vcr.ttf"), 20);
visualOffsetText.x = (FlxG.height / 8) + 10;
visualOffsetText.y = 10;
visualOffsetText.fieldWidth = strumLine.x - visualOffsetText.x - 10;
add(visualOffsetText);
offsetText = new FlxText();
offsetText.setFormat(Paths.font("vcr.ttf"), 20);
offsetText.x = strumLine.x + strumLine.width + 10;
offsetText.y = 10;
offsetText.fieldWidth = FlxG.width - offsetText.x - 10;
add(offsetText);
2024-02-12 20:06:43 -05:00
var helpText:FlxText = new FlxText();
helpText.setFormat(Paths.font("vcr.ttf"), 20);
helpText.text = "Press ESC to return to main menu";
helpText.x = FlxG.width - helpText.width;
2024-02-19 20:56:57 -05:00
helpText.y = FlxG.height - (helpText.height * 2) - 2;
2024-02-12 20:06:43 -05:00
add(helpText);
2024-01-16 05:37:06 -05:00
regenNoteData();
}
2024-02-12 20:06:43 -05:00
function preciseInputPressed(event:PreciseInputEvent)
{
generateBeatStuff(event);
strumLine.pressKey(event.noteDirection);
strumLine.playPress(event.noteDirection);
}
function preciseInputReleased(event:PreciseInputEvent)
{
strumLine.playStatic(event.noteDirection);
strumLine.releaseKey(event.noteDirection);
}
override public function close():Void
{
PreciseInputManager.instance.onInputPressed.remove(preciseInputPressed);
PreciseInputManager.instance.onInputReleased.remove(preciseInputReleased);
FlxG.sound.music.volume = previousVolume;
swagSong.stop();
FlxG.sound.list.remove(swagSong);
2024-02-12 20:06:43 -05:00
FlxG.cameras.remove(stateCamera);
FlxG.state.persistentDraw = prevPersistentDraw;
FlxG.state.persistentUpdate = prevPersistentUpdate;
2024-02-12 20:06:43 -05:00
super.close();
}
2024-01-16 05:37:06 -05:00
function regenNoteData()
{
for (i in 0...32)
{
var note:SongNoteData = new SongNoteData((localConductor.stepLengthMs * 2) * i, 1);
2024-01-16 05:37:06 -05:00
noteGrp.push(note);
}
strumLine.applyNoteData(noteGrp);
}
override function stepHit():Bool
{
if (localConductor.currentStep % 4 == 2)
{
blocks.members[((localConductor.currentBeat % 8) + 1) % 8].alpha = 0.5;
}
return super.stepHit();
}
override function beatHit():Bool
{
if (localConductor.currentBeat % 8 == 0) blocks.forEach(blok -> {
2024-02-10 15:42:29 -05:00
blok.alpha = 0.1;
});
blocks.members[localConductor.currentBeat % 8].alpha = 1;
// block.visible = !block.visible;
return super.beatHit();
}
override function update(elapsed:Float)
{
/* trace("1: " + swagSong.frfrTime);
@:privateAccess
trace(FlxG.sound.music._channel.position);
*/
2024-04-04 19:46:08 -04:00
localConductor.update(swagSong.time, false);
// localConductor.songPosition += (Timer.stamp() * 1000) - FlxG.sound.music.prevTimestamp;
songPosVis.x = songPosToX(localConductor.songPosition);
2024-02-12 22:14:35 -05:00
songVisFollowAudio.x = songPosToX(localConductor.songPosition - localConductor.audioVisualOffset);
songVisFollowVideo.x = songPosToX(localConductor.songPosition - localConductor.inputOffset);
2024-02-12 22:14:35 -05:00
visualOffsetText.text = "Visual Offset: " + localConductor.audioVisualOffset + "ms";
2024-02-12 22:44:59 -05:00
visualOffsetText.text += "\n\nYou can press SPACE+Left/Right to change this value.";
visualOffsetText.text += "\n\nYou can hold SHIFT to step 1ms at a time";
2024-02-10 15:42:29 -05:00
offsetText.text = "INPUT Offset (Left/Right to change): " + localConductor.inputOffset + "ms";
2024-02-12 22:44:59 -05:00
offsetText.text += "\n\nYou can hold SHIFT to step 1ms at a time";
var avgOffsetInput:Float = 0;
2024-02-14 08:29:38 -05:00
var loopInd:Int = 0;
for (offsetThing in offsetsPerBeat)
2024-02-14 08:29:38 -05:00
{
if (offsetThing == null) continue;
avgOffsetInput += offsetThing;
2024-02-14 08:29:38 -05:00
loopInd++;
}
2024-02-14 08:29:38 -05:00
avgOffsetInput /= loopInd;
2024-02-12 22:44:59 -05:00
offsetText.text += "\n\nEstimated average input offset needed: " + avgOffsetInput;
2024-01-09 19:57:33 -05:00
var multiply:Int = 10;
if (FlxG.keys.pressed.SHIFT) multiply = 1;
2023-12-12 23:28:16 -05:00
if (FlxG.keys.pressed.CONTROL || FlxG.keys.pressed.SPACE)
{
if (FlxG.keys.justPressed.RIGHT)
{
2024-02-12 22:14:35 -05:00
localConductor.audioVisualOffset += 1 * multiply;
}
if (FlxG.keys.justPressed.LEFT)
{
2024-02-12 22:14:35 -05:00
localConductor.audioVisualOffset -= 1 * multiply;
}
}
else
{
2024-02-19 20:56:57 -05:00
if (FlxG.keys.anyJustPressed([LEFT, RIGHT]))
{
2024-02-19 20:56:57 -05:00
if (FlxG.keys.justPressed.RIGHT)
{
localConductor.inputOffset += 1 * multiply;
}
if (FlxG.keys.justPressed.LEFT)
{
localConductor.inputOffset -= 1 * multiply;
}
// reset the average, so you don't need to wait a full loop to start getting averages
// also reset each text member
offsetsPerBeat = [];
diffGrp.forEach(memb -> memb.text = "");
}
}
2024-02-12 20:06:43 -05:00
if (FlxG.keys.justPressed.ESCAPE)
{
close();
}
super.update(elapsed);
}
2024-01-09 13:16:00 -05:00
function generateBeatStuff(event:PreciseInputEvent)
{
// localConductor.update(swagSong.getTimeWithDiff());
2024-01-09 13:16:00 -05:00
var inputLatencyMs:Float = haxe.Int64.toInt(PreciseInputManager.getCurrentTimestamp() - event.timestamp) / 1000.0 / 1000.0;
2024-02-12 22:14:35 -05:00
// trace("input latency: " + inputLatencyMs + "ms");
// trace("cur timestamp: " + PreciseInputManager.getCurrentTimestamp() + "ns");
// trace("event timestamp: " + event.timestamp + "ns");
// trace("songtime: " + localConductor.getTimeWithDiff(swagSong) + "ms");
var closestBeat:Int = Math.round(localConductor.getTimeWithDiff(swagSong) / (localConductor.stepLengthMs * 2)) % diffGrp.members.length;
var getDiff:Float = localConductor.getTimeWithDiff(swagSong) - (closestBeat * (localConductor.stepLengthMs * 2));
// getDiff -= localConductor.inputOffset;
2024-01-09 13:16:00 -05:00
getDiff -= inputLatencyMs;
2024-02-12 22:44:59 -05:00
getDiff -= localConductor.audioVisualOffset;
// lil fix for end of song
if (closestBeat == 0 && getDiff >= localConductor.stepLengthMs * 2) getDiff -= swagSong.length;
beatTrail.x = songPosVis.x;
diffGrp.members[closestBeat].text = getDiff + "ms";
2024-01-27 06:16:46 -05:00
offsetsPerBeat[closestBeat] = Math.round(getDiff);
}
function songPosToX(pos:Float):Float
{
2024-02-12 20:06:43 -05:00
return FlxMath.remapToRange(pos, 0, swagSong.length, 0, FlxG.width);
}
2020-10-06 21:56:14 -04:00
}
2022-07-12 19:02:38 -04:00
class HomemadeMusic extends FlxSound
{
public var prevTimestamp:Int = 0;
public function new()
{
super();
}
var prevTime:Float = 0;
override function update(elapsed:Float)
{
super.update(elapsed);
if (prevTime != time)
{
prevTime = time;
prevTimestamp = Std.int(Timer.stamp() * 1000);
}
}
public function getTimeWithDiff():Float
{
return time + (Std.int(Timer.stamp() * 1000) - prevTimestamp);
}
2022-07-12 19:02:38 -04:00
}