From cdc23f08099b829754edd326911c059c50834e6a Mon Sep 17 00:00:00 2001 From: MasterEric Date: Sat, 24 Sep 2022 01:28:39 -0400 Subject: [PATCH] Working new chart format (not working everything else :') ) --- source/funkin/Conductor.hx | 31 ++++--- source/funkin/FreeplayState.hx | 2 +- source/funkin/MusicBeatState.hx | 25 +++--- source/funkin/SongLoad.hx | 19 +---- source/funkin/TitleState.hx | 13 +-- source/funkin/VoicesGroup.hx | 11 +-- source/funkin/charting/ChartingState.hx | 18 ++--- source/funkin/play/PlayState.hx | 103 +++++++++++++----------- source/funkin/play/song/Song.hx | 25 +++--- source/funkin/play/song/SongData.hx | 22 ++--- 10 files changed, 125 insertions(+), 144 deletions(-) diff --git a/source/funkin/Conductor.hx b/source/funkin/Conductor.hx index a9290dc16..1e2210d53 100644 --- a/source/funkin/Conductor.hx +++ b/source/funkin/Conductor.hx @@ -3,7 +3,6 @@ package funkin; import flixel.util.FlxSignal; import funkin.SongLoad.SwagSong; import funkin.play.song.Song.SongDifficulty; -import funkin.play.song.SongData.ConductorTimeChange; import funkin.play.song.SongData.SongTimeChange; typedef BPMChangeEvent = @@ -68,9 +67,9 @@ class Conductor return crochet / 4; } - public static var currentBeat(get, null):Float; + public static var currentBeat(get, null):Int; - static function get_currentBeat():Float + static function get_currentBeat():Int { return currentBeat; } @@ -127,20 +126,28 @@ class Conductor var oldBeat = currentBeat; var oldStep = currentStep; - songPosition = songPosition; - bpm = Conductor.getLastBPMChange().bpm; + Conductor.songPosition = songPosition; + Conductor.bpm = Conductor.getLastBPMChange().bpm; + currentTimeChange = timeChanges[0]; for (i in 0...timeChanges.length) { - if (songPosition >= timeChanges[i].songTime) + if (songPosition >= timeChanges[i].timeStamp) currentTimeChange = timeChanges[i]; - if (songPosition < timeChanges[i].songTime) + if (songPosition < timeChanges[i].timeStamp) break; } - currentStep = (currentTimeChange.beatTime * 4) + (songPosition - currentTimeChange.songTime) / stepCrochet; - currentBeat = Math.floor(currentStep / 4); + if (currentTimeChange == null) + { + trace('WARNING: Conductor is broken, timeChanges is empty.'); + } + else + { + currentStep = Math.floor((currentTimeChange.beatTime * 4) + (songPosition - currentTimeChange.timeStamp) / stepCrochet); + currentBeat = Math.floor(currentStep / 4); + } // FlxSignals are really cool. if (currentStep != oldStep) @@ -183,9 +190,9 @@ class Conductor timeChanges = []; - for (currentTimeChange in timeChanges) + for (currentTimeChange in songTimeChanges) { - var prevTimeChange:SongTimeChange = timeChanges.length == 0 ? null : timeChanges[timeChanges.length - 1]; + // var prevTimeChange:SongTimeChange = timeChanges.length == 0 ? null : timeChanges[timeChanges.length - 1]; /* if (prevTimeChange != null) @@ -205,6 +212,8 @@ class Conductor timeChanges.push(currentTimeChange); } + trace('Done mapping time changes: ' + timeChanges); + // Done. } } diff --git a/source/funkin/FreeplayState.hx b/source/funkin/FreeplayState.hx index fbb90ed98..607f31b47 100644 --- a/source/funkin/FreeplayState.hx +++ b/source/funkin/FreeplayState.hx @@ -98,7 +98,7 @@ class FreeplayState extends MusicBeatSubstate } if (StoryMenuState.weekUnlocked[2] || isDebug) - addWeek(['Bopeebo', 'Bopeebo_new', 'Fresh', 'Dadbattle'], 1, ['dad']); + addWeek(['Bopeebo', 'Fresh', 'Dadbattle'], 1, ['dad']); if (StoryMenuState.weekUnlocked[2] || isDebug) addWeek(['Spookeez', 'South', 'Monster'], 2, ['spooky', 'spooky', 'monster']); diff --git a/source/funkin/MusicBeatState.hx b/source/funkin/MusicBeatState.hx index 3967017ac..a2f1c8437 100644 --- a/source/funkin/MusicBeatState.hx +++ b/source/funkin/MusicBeatState.hx @@ -6,7 +6,6 @@ import flixel.addons.ui.FlxUIState; import flixel.text.FlxText; import flixel.util.FlxColor; import flixel.util.FlxSort; -import funkin.Conductor.BPMChangeEvent; import funkin.modding.PolymodHandler; import funkin.modding.events.ScriptEvent; import funkin.modding.module.ModuleHandler; @@ -19,8 +18,6 @@ import funkin.util.SortUtil; */ class MusicBeatState extends FlxUIState { - private var curStep:Int = 0; - private var curBeat:Int = 0; private var controls(get, never):Controls; inline function get_controls():Controls @@ -47,6 +44,16 @@ class MusicBeatState extends FlxUIState super.create(); createWatermarkText(); + + Conductor.beatHit.add(this.beatHit); + Conductor.stepHit.add(this.stepHit); + } + + public override function destroy():Void + { + super.destroy(); + Conductor.beatHit.remove(this.beatHit); + Conductor.stepHit.remove(this.stepHit); } override function update(elapsed:Float) @@ -69,14 +76,7 @@ class MusicBeatState extends FlxUIState FlxG.state.openSubState(new DebugMenuSubState()); } - // everyStep(); - var oldStep:Int = curStep; - - updateCurStep(); - updateBeat(); - - if (oldStep != curStep && curStep >= 0) - stepHit(); + // Conductor.update(FlxG.sound.music.time + Conductor.offset); FlxG.watch.addQuick("songPos", Conductor.songPosition); @@ -124,9 +124,6 @@ class MusicBeatState extends FlxUIState if (event.eventCanceled) return false; - if (Conductor.currentStep % 4 == 0) - beatHit(); - return true; } diff --git a/source/funkin/SongLoad.hx b/source/funkin/SongLoad.hx index acbeaab09..b4cbc3c26 100644 --- a/source/funkin/SongLoad.hx +++ b/source/funkin/SongLoad.hx @@ -48,7 +48,7 @@ class SongLoad public static function loadFromJson(jsonInput:String, ?folder:String):SwagSong { - var rawJson:Dynamic = null; + var rawJson:String = null; try { rawJson = Assets.getText(Paths.json('songs/${folder.toLowerCase()}/${jsonInput.toLowerCase()}')).trim(); @@ -67,25 +67,8 @@ class SongLoad while (!rawJson.endsWith("}")) { rawJson = rawJson.substr(0, rawJson.length - 1); - // LOL GOING THROUGH THE BULLSHIT TO CLEAN IDK WHATS STRANGE } - // FIX THE CASTING ON WINDOWS/NATIVE - // Windows??? - // trace(songData); - - // trace('LOADED FROM JSON: ' + songData.notes); - /* - for (i in 0...songData.notes.length) - { - trace('LOADED FROM JSON: ' + songData.notes[i].sectionNotes); - // songData.notes[i].sectionNotes = songData.notes[i].sectionNotes - } - - daNotes = songData.notes; - daSong = songData.song; - daBpm = songData.bpm; */ - return parseJSONshit(rawJson); } diff --git a/source/funkin/TitleState.hx b/source/funkin/TitleState.hx index 200198f5c..6ecc6432e 100644 --- a/source/funkin/TitleState.hx +++ b/source/funkin/TitleState.hx @@ -530,12 +530,13 @@ class TitleState extends MusicBeatState if (!skippedIntro) { - FlxG.log.add(curBeat); + // FlxG.log.add(Conductor.currentBeat); // if the user is draggin the window some beats will // be missed so this is just to compensate - if (curBeat > lastBeat) + if (Conductor.currentBeat > lastBeat) { - for (i in lastBeat...curBeat) + // TODO: Why does it perform ALL the previous steps each beat? + for (i in lastBeat...Conductor.currentBeat) { switch (i + 1) { @@ -572,14 +573,14 @@ class TitleState extends MusicBeatState } } } - lastBeat = curBeat; + lastBeat = Conductor.currentBeat; } if (skippedIntro) { - if (cheatActive && curBeat % 2 == 0) + if (cheatActive && Conductor.currentBeat % 2 == 0) swagShader.update(0.125); - if (logoBl != null) + if (logoBl != null && logoBl.animation != null) logoBl.animation.play('bump', true); danceLeft = !danceLeft; diff --git a/source/funkin/VoicesGroup.hx b/source/funkin/VoicesGroup.hx index ae34bb0c6..306d82900 100644 --- a/source/funkin/VoicesGroup.hx +++ b/source/funkin/VoicesGroup.hx @@ -14,22 +14,17 @@ class VoicesGroup extends FlxTypedGroup public var pitch(default, set):Float = 1; // make it a group that you add to? - public function new(song:String, ?files:Array, ?needsVoices:Bool = true) + public function new(song:String, ?files:Array = null) { super(); - if (!needsVoices) + if (files == null) { - // simply adds an empty sound? fills it in moreso for easier backwards compatibility + // Add an empty voice. add(new FlxSound()); - // FlxG.sound.list.add(snd); - return; } - if (files == null) - files = [""]; // loads with no file name assumption, to load "Voices.ogg" or whatev normally - for (sndFile in files) { var snd:FlxSound = new FlxSound().loadEmbedded(Paths.voices(song, '$sndFile')); diff --git a/source/funkin/charting/ChartingState.hx b/source/funkin/charting/ChartingState.hx index cb0faa74e..57059f5c8 100644 --- a/source/funkin/charting/ChartingState.hx +++ b/source/funkin/charting/ChartingState.hx @@ -622,7 +622,7 @@ class ChartingState extends MusicBeatState FlxG.sound.music.pan = FlxMath.remapToRange(FlxG.mouse.screenX, 0, FlxG.width, -1, 1) * 10; - curStep = recalculateSteps(); + // curStep = recalculateSteps(); Conductor.songPosition = FlxG.sound.music.time; _song.song = typingShit.text; @@ -649,7 +649,7 @@ class ChartingState extends MusicBeatState if (FlxG.keys.justPressed.X) toggleAltAnimNote(); - if (curBeat % 4 == 0 && curStep >= 16 * (curSection + 1)) + if (false) // (curBeat % 4 == 0 && curStep >= 16 * (curSection + 1)) { // trace(curStep); // trace((SongLoad.getSong()[curSection].lengthInSteps) * (curSection + 1)); @@ -663,8 +663,8 @@ class ChartingState extends MusicBeatState changeSection(curSection + 1, false); } - FlxG.watch.addQuick('daBeat', curBeat); - FlxG.watch.addQuick('daStep', curStep); + FlxG.watch.addQuick('daBeat', Conductor.currentBeat); + FlxG.watch.addQuick('daStep', Conductor.currentStep); if (FlxG.mouse.pressedMiddle && FlxG.mouse.overlaps(gridBG)) { @@ -1034,10 +1034,10 @@ class ChartingState extends MusicBeatState lastChange = Conductor.bpmChangeMap[i]; } - curStep = lastChange.stepTime + Math.floor((FlxG.sound.music.time - lastChange.songTime) / Conductor.stepCrochet); - updateBeat(); + // curStep = lastChange.stepTime + Math.floor((FlxG.sound.music.time - lastChange.songTime) / Conductor.stepCrochet); + // updateBeat(); - return curStep; + return Conductor.currentStep; } function resetSection(songBeginning:SongResetType = SECTION):Void @@ -1061,7 +1061,7 @@ class ChartingState extends MusicBeatState } vocals.time = FlxG.sound.music.time; - updateCurStep(); + // updateCurStep(); updateGrid(); updateSectionUI(); @@ -1092,7 +1092,7 @@ class ChartingState extends MusicBeatState FlxG.sound.music.time = sectionStartTime(); vocals.time = FlxG.sound.music.time; - updateCurStep(); + // updateCurStep(); } updateGrid(); diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 5fbfccde1..c7eb0cc1f 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -336,8 +336,6 @@ class PlayState extends MusicBeatState FlxG.sound.cache(Paths.voices(currentSong.song)); } - Conductor.update(-5000); - // Initialize stage stuff. initCameras(); @@ -369,6 +367,8 @@ class PlayState extends MusicBeatState } } + Conductor.update(-5000); + if (dialogue != null) { doof = new DialogueBox(false, dialogue); @@ -989,6 +989,7 @@ class PlayState extends MusicBeatState } FlxG.sound.music.onComplete = endSong; + trace('Playing vocals...'); vocals.play(); #if discord_rpc @@ -1011,13 +1012,15 @@ class PlayState extends MusicBeatState if (currentSong.needsVoices) vocals = new VoicesGroup(currentSong.song, currentSong.voiceList); else - vocals = new VoicesGroup(currentSong.song, null, false); + vocals = new VoicesGroup(currentSong.song, null); vocals.members[0].onComplete = function() { vocalsFinished = true; }; + trace(vocals); + activeNotes = new FlxTypedGroup(); activeNotes.zIndex = 1000; add(activeNotes); @@ -1525,8 +1528,8 @@ class PlayState extends MusicBeatState camHUD.zoom = FlxMath.lerp(1 * FlxCamera.defaultZoom, camHUD.zoom, 0.95); } - FlxG.watch.addQuick("beatShit", curBeat); - FlxG.watch.addQuick("stepShit", curStep); + FlxG.watch.addQuick("beatShit", Conductor.currentBeat); + FlxG.watch.addQuick("stepShit", Conductor.currentStep); if (currentStage != null) { FlxG.watch.addQuick("bfAnim", currentStage.getBoyfriend().getCurrentAnimation()); @@ -1535,7 +1538,7 @@ class PlayState extends MusicBeatState if (currentSong != null && currentSong.song == 'Fresh') { - switch (curBeat) + switch (Conductor.currentBeat) { case 16: camZooming = true; @@ -1758,20 +1761,10 @@ class PlayState extends MusicBeatState { FlxG.sound.music.pause(); - var daBPM:Float = currentSong.bpm; - var daPos:Float = 0; - for (i in 0...(Std.int(curStep / 16 + sec))) - { - if (SongLoad.getSong()[i].changeBPM) - { - daBPM = SongLoad.getSong()[i].bpm; - } - daPos += 4 * (1000 * 60 / daBPM); - } + // BPM might change between the current and target section but IDGAF + FlxG.sound.music.time = Conductor.songPosition + (sec * 4 * (1000 * 60 / Conductor.bpm)); - FlxG.sound.music.time = daPos; Conductor.update(FlxG.sound.music.time + Conductor.offset); - updateCurStep(); resyncVocals(); } #end @@ -1785,7 +1778,7 @@ class PlayState extends MusicBeatState mayPauseGame = false; FlxG.sound.music.volume = 0; vocals.volume = 0; - if (currentSong.validScore) + if (currentSong != null && currentSong.validScore) { Highscore.saveScore(currentSong.song, songScore, storyDifficulty); } @@ -2186,8 +2179,8 @@ class PlayState extends MusicBeatState resyncVocals(); } - iconP1.onStepHit(curStep); - iconP2.onStepHit(curStep); + iconP1.onStepHit(Conductor.currentStep); + iconP2.onStepHit(Conductor.currentStep); return true; } @@ -2204,18 +2197,21 @@ class PlayState extends MusicBeatState } // Moving this code into the `beatHit` function allows for scripts and modules to control the camera better. - if (generatedMusic && SongLoad.getSong()[Std.int(curStep / 16)] != null) + if (currentSong != null) { - cameraRightSide = SongLoad.getSong()[Std.int(curStep / 16)].mustHitSection; - controlCamera(); - } - - if (SongLoad.getSong()[Math.floor(curStep / 16)] != null) - { - if (SongLoad.getSong()[Math.floor(curStep / 16)].changeBPM) + if (generatedMusic && SongLoad.getSong()[Std.int(Conductor.currentStep / 16)] != null) { - Conductor.forceBPM(SongLoad.getSong()[Math.floor(curStep / 16)].bpm); - FlxG.log.add('CHANGED BPM!'); + cameraRightSide = SongLoad.getSong()[Std.int(Conductor.currentStep / 16)].mustHitSection; + controlCamera(); + } + + if (SongLoad.getSong()[Math.floor(Conductor.currentStep / 16)] != null) + { + if (SongLoad.getSong()[Math.floor(Conductor.currentStep / 16)].changeBPM) + { + Conductor.forceBPM(SongLoad.getSong()[Math.floor(Conductor.currentStep / 16)].bpm); + FlxG.log.add('CHANGED BPM!'); + } } } @@ -2223,13 +2219,18 @@ class PlayState extends MusicBeatState if (PreferencesMenu.getPref('camera-zoom')) { - if (currentSong.song.toLowerCase() == 'milf' && curBeat >= 168 && curBeat < 200 && camZooming && FlxG.camera.zoom < 1.35) + if (currentSong != null + && currentSong.song.toLowerCase() == 'milf' + && Conductor.currentBeat >= 168 + && Conductor.currentBeat < 200 + && camZooming + && FlxG.camera.zoom < 1.35) { FlxG.camera.zoom += 0.015 * FlxCamera.defaultZoom; camHUD.zoom += 0.03; } - if (camZooming && FlxG.camera.zoom < (1.35 * FlxCamera.defaultZoom) && curBeat % 4 == 0) + if (camZooming && FlxG.camera.zoom < (1.35 * FlxCamera.defaultZoom) && Conductor.currentBeat % 4 == 0) { FlxG.camera.zoom += 0.015 * FlxCamera.defaultZoom; camHUD.zoom += 0.03; @@ -2242,14 +2243,19 @@ class PlayState extends MusicBeatState // bruh this var is bonkers i thot it was a function lmfaooo // Break up into individual lines to aid debugging. - var shouldShowComboText:Bool = (curBeat % 8 == 7); - var daSection = SongLoad.getSong()[Std.int(curStep / 16)]; - shouldShowComboText = shouldShowComboText && (daSection != null && daSection.mustHitSection); - shouldShowComboText = shouldShowComboText && (combo > 5); - var daNextSection = SongLoad.getSong()[Std.int(curStep / 16) + 1]; - var isEndOfSong = SongLoad.getSong().length < Std.int(curStep / 16); - shouldShowComboText = shouldShowComboText && (isEndOfSong || (daNextSection != null && !daNextSection.mustHitSection)); + var shouldShowComboText:Bool = false; + if (currentSong != null) + { + shouldShowComboText = (Conductor.currentBeat % 8 == 7); + var daSection = SongLoad.getSong()[Std.int(Conductor.currentBeat / 16)]; + shouldShowComboText = shouldShowComboText && (daSection != null && daSection.mustHitSection); + shouldShowComboText = shouldShowComboText && (combo > 5); + + var daNextSection = SongLoad.getSong()[Std.int(Conductor.currentBeat / 16) + 1]; + var isEndOfSong = SongLoad.getSong().length < Std.int(Conductor.currentBeat / 16); + shouldShowComboText = shouldShowComboText && (isEndOfSong || (daNextSection != null && !daNextSection.mustHitSection)); + } if (shouldShowComboText) { @@ -2282,17 +2288,16 @@ class PlayState extends MusicBeatState return; // TODO: Move this to a song event. - if (curBeat % 8 == 7 && currentSong.song == 'Bopeebo') - { - currentStage.getBoyfriend().playAnimation('hey', true); - } + // if (Conductor.currentBeat % 8 == 7 && currentSong.song == 'Bopeebo') + // { + // currentStage.getBoyfriend().playAnimation('hey', true); + // } // TODO: Move this to a song event. - if (curBeat % 16 == 15 - && currentSong.song == 'Tutorial' + if (Conductor.currentBeat % 16 == 15 // && currentSong.song == 'Tutorial' && currentStage.getDad().characterId == 'gf' - && curBeat > 16 - && curBeat < 48) + && Conductor.currentBeat > 16 + && Conductor.currentBeat < 48) { currentStage.getBoyfriend().playAnimation('hey', true); currentStage.getDad().playAnimation('cheer', true); @@ -2478,7 +2483,7 @@ class PlayState extends MusicBeatState if (currentChart != null) { } - else + else if (currentSong != null) { openfl.utils.Assets.cache.clear(Paths.inst(currentSong.song)); openfl.utils.Assets.cache.clear(Paths.voices(currentSong.song)); diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 56053bcf8..f19a2b9bc 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -204,30 +204,29 @@ class SongDifficulty public inline function cacheInst() { - // DEBUG: Remove this. - // FlxG.sound.cache(Paths.inst(this.song.songId)); - FlxG.sound.cache(Paths.inst('bopeebo')); + FlxG.sound.cache(Paths.inst(this.song.songId)); } public inline function playInst(volume:Float = 1.0, looped:Bool = false) { - // DEBUG: Remove this. - // FlxG.sound.playMusic(Paths.inst(this.song.songId), volume, looped); - FlxG.sound.playMusic(Paths.inst('bopeebo'), volume, looped); + FlxG.sound.playMusic(Paths.inst(this.song.songId), volume, looped); } public inline function cacheVocals() { - // DEBUG: Remove this. - // FlxG.sound.cache(Paths.voices(this.song.songId)); - FlxG.sound.cache(Paths.voices('bopeebo')); + FlxG.sound.cache(Paths.voices(this.song.songId)); } - public inline function buildVocals(charId:String = "bf"):VoicesGroup + public function buildVoiceList():Array { - // DEBUG: Remove this. - // var result:VoicesGroup = new VoicesGroup(this.song.songId, null, false); - var result:VoicesGroup = new VoicesGroup('bopeebo', null, false); + // TODO: Implement. + + return [""]; + } + + public function buildVocals(charId:String = "bf"):VoicesGroup + { + var result:VoicesGroup = new VoicesGroup(this.song.songId, this.buildVoiceList()); return result; } } diff --git a/source/funkin/play/song/SongData.hx b/source/funkin/play/song/SongData.hx index 601051970..58a2f8d44 100644 --- a/source/funkin/play/song/SongData.hx +++ b/source/funkin/play/song/SongData.hx @@ -22,7 +22,7 @@ class SongDataParser static final DEFAULT_SONG_ID = 'UNKNOWN'; static final SONG_DATA_PATH = 'songs/'; - static final SONG_DATA_SUFFIX = '/metadata.json'; + static final SONG_DATA_SUFFIX = '-metadata.json'; /** * Parses and preloads the game's song metadata and scripts when the game starts. @@ -56,7 +56,10 @@ class SongDataParser // // UNSCRIPTED SONGS // - var songIdList:Array = DataAssets.listDataFilesInPath(SONG_DATA_PATH, SONG_DATA_SUFFIX); + var songIdList:Array = DataAssets.listDataFilesInPath(SONG_DATA_PATH, SONG_DATA_SUFFIX).map(function(songDataPath:String):String + { + return songDataPath.split('/')[0]; + }); var unscriptedSongIds:Array = songIdList.filter(function(songId:String):Bool { return !songCache.exists(songId); @@ -154,7 +157,7 @@ class SongDataParser static function loadSongMetadataFile(songPath:String, variation:String = ''):String { - var songMetadataFilePath:String = (variation != '') ? Paths.json('$SONG_DATA_PATH$songPath/metadata-$variation') : Paths.json('$SONG_DATA_PATH$songPath/metadata'); + var songMetadataFilePath:String = (variation != '') ? Paths.json('$SONG_DATA_PATH$songPath/$songPath-metadata-$variation') : Paths.json('$SONG_DATA_PATH$songPath/$songPath-metadata'); var rawJson:String = Assets.getText(songMetadataFilePath).trim(); @@ -192,7 +195,7 @@ class SongDataParser static function loadSongChartDataFile(songPath:String, variation:String = ''):String { - var songChartDataFilePath:String = (variation != '') ? Paths.json('$SONG_DATA_PATH$songPath/chart-$variation') : Paths.json('$SONG_DATA_PATH$songPath/chart'); + var songChartDataFilePath:String = (variation != '') ? Paths.json('$SONG_DATA_PATH$songPath/$songPath-chart-$variation') : Paths.json('$SONG_DATA_PATH$songPath/$songPath-chart'); var rawJson:String = Assets.getText(songChartDataFilePath).trim(); @@ -600,17 +603,6 @@ typedef RawSongTimeChange = var bt:OneOfTwo>; } -typedef RawConductorTimeChange = -{ - > RawSongTimeChange, - - /** - * The time in the song (in steps) that this change occurs at. - * This time is somewhat weird because the rate it increases is dependent on the BPM at that point in the song. - */ - public var st:Float; -} - /** * Add aliases to the minimalized property names of the typedef, * to improve readability.