From 8da7faa0b48accf542df0c4675cbfc6f37b17d3c Mon Sep 17 00:00:00 2001 From: NyxieFemboy Date: Sun, 6 Oct 2024 15:10:51 -0400 Subject: [PATCH] time Signature functionality wip --- assets/fonts/timeSig.ttf | Bin 0 -> 6927 bytes .../event-icons/Time Signature Change.png | Bin 0 -> 222 bytes source/funkin/backend/chart/Chart.hx | 1 + source/funkin/backend/chart/EventsData.hx | 3 +- .../funkin/backend/chart/FNFLegacyParser.hx | 15 ++- source/funkin/backend/system/Conductor.hx | 125 +++++++++++++----- source/funkin/editors/charter/CharterEvent.hx | 2 +- source/funkin/game/PlayState.hx | 1 + 8 files changed, 112 insertions(+), 35 deletions(-) create mode 100644 assets/fonts/timeSig.ttf create mode 100644 assets/images/editors/charter/event-icons/Time Signature Change.png diff --git a/assets/fonts/timeSig.ttf b/assets/fonts/timeSig.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9729308fcb613c44fb13cff7b9d9aace314d2469 GIT binary patch literal 6927 zcmeHLOK%%h6#i!Hq)v*{f?I-$L`OVIRUma9O%nlXp;fCuQBa&l4M@*6ZckYdAsY~>I!D}?nj&3{FNBuUhC-cSH(oN@t>srcLbUigDC z>;SI3_{(!EWvtbofE|no#>CKMNUXtIBNp_i5n)RPkx5MBV9;lW9#L%jmh}O;5Vx5Y zXf|4s`Y;qax)uq)D`#K2Fo4sneq7hkDoU+InnR`0x-3dnC2MR+vDc9dQKhKR1H7w@ zZ?TM5C=>iszNDJBsg|y^bhFvK-TbL}vsD6nH)`9LY0WIwS1dbC%=nyiliNfd=sn8^ z^BWd=8R+{{JzrcEagM14#;}J^?LMT?k4JHsPtDVK2FHp0Nj#5JID_+e6_X@(yIa6a zvq63usv1HWNb(fOJ7Q}oaU>(~|E=T1?$jUV*Lh@q$)m_;buv4Z2)nVvesli)YCfAR zMsm1i?gSH&f|YO;+8V7W`;Nw(8!13dY{_rRj=3eLRZ;vkX#gZ(1UyI?E(Mz9xK z{1R_#uEZ9``e9|JpTd?P0Yj=4x;vha3oyF{*&>NPo%`lSs9go z4TplAiLGf%oJiAe+7c(y^qaQCrPMRh!Fy}VC*R7KUWlr(BLwBpug?uZJ<1=o!({xL zQ&rcohP8I+35uQiHyaQ2o3A6jCXv~JUm7G)xM?S4M+q10xRdc=yykkxcVIj2Hp`9V zGo_i&v?U&Rumf(lXCG>;g@bTE=zSoZ$bOMH;U+x&bRIKK>@bhcEAvRc$os@#l3tI1{{+`x*s9)E5 zFJ8x|T2EpCe5iw#!U5}9{e8wl(mJhm8+)wRv>s#swASM|Xt`SN!d`1p>)q7f)p`&0 z_qE=Oqt=I7Pom%YQtK)7THo`3bSvJ&o=f>qmL@*Q8PFgB>L$vb8CK?J%eS&)=^>Hk)S#ci@3UU7~%8E^4o)thtX z%f3^~dyb?ixwX3QIoZ5h%6ZO2wp^;tmg`R5UG##uisu&#Rh2kBI5a$RV)W$Lc!=&U gznkKhCxd!PsWz{^hp*eLb$fR^cM;e{pdAAL05Fqxl>h($ literal 0 HcmV?d00001 diff --git a/assets/images/editors/charter/event-icons/Time Signature Change.png b/assets/images/editors/charter/event-icons/Time Signature Change.png new file mode 100644 index 0000000000000000000000000000000000000000..f7cc46c7805274d13ea1e4b09a9c678fe0285633 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G}c0G|+7ApQUUe;`?Wtho?KF_#4S1p@`HpW+3oW#BCEh%9Dc;5!Jyj5{V~ zzXb~Vd%8G=Xav{xd-E|EayVW5Eng)tqt489<23P$Vs8^#-!W<|$U4GyN_|1=gbP0 Hl+XkKO;<(} literal 0 HcmV?d00001 diff --git a/source/funkin/backend/chart/Chart.hx b/source/funkin/backend/chart/Chart.hx index bd13fd50..e2a22d40 100644 --- a/source/funkin/backend/chart/Chart.hx +++ b/source/funkin/backend/chart/Chart.hx @@ -129,6 +129,7 @@ class Chart { 1 => "Camera Movement", 2 => "BPM Change", 3 => "Alt Animation Toggle", + 4 => "Time Signature Change", ]; if (data.events == null) data.events = []; diff --git a/source/funkin/backend/chart/EventsData.hx b/source/funkin/backend/chart/EventsData.hx index d443218a..e0d17331 100644 --- a/source/funkin/backend/chart/EventsData.hx +++ b/source/funkin/backend/chart/EventsData.hx @@ -10,7 +10,7 @@ import funkin.backend.assets.Paths; using StringTools; class EventsData { - public static var defaultEventsList:Array = ["HScript Call", "Camera Movement", "Add Camera Zoom", "Camera Modulo Change", "Camera Flash", "BPM Change", "Scroll Speed Change", "Alt Animation Toggle", "Play Animation"]; + public static var defaultEventsList:Array = ["HScript Call", "Camera Movement", "Add Camera Zoom", "Camera Modulo Change", "Camera Flash", "BPM Change", "Scroll Speed Change", "Alt Animation Toggle", "Play Animation", "Time Signature Change"]; public static var defaultEventsParams:Map> = [ "HScript Call" => [ {name: "Function Name", type: TString, defValue: "myFunc"}, @@ -49,6 +49,7 @@ class EventsData { ], "Alt Animation Toggle" => [{name: "Enable On Sing Poses", type: TBool, defValue: true}, {name: "Enable On Idle", type: TBool, defValue: true}, {name: "Strumline", type: TStrumLine, defValue: 0}], "Play Animation" => [{name: "Character", type: TStrumLine, defValue: 0}, {name: "Animation", type: TString, defValue: "animation"}, {name: "Is forced?", type: TBool, defValue: true}], + "Time Signature Change" => [{name: "Target Beat Count", type: TFloat(1), defValue: 4}, {name: "Target Step Count", type: TFloat(1), defValue: 4}], ]; public static var eventsList:Array = defaultEventsList.copy(); diff --git a/source/funkin/backend/chart/FNFLegacyParser.hx b/source/funkin/backend/chart/FNFLegacyParser.hx index ede54e18..d7560228 100644 --- a/source/funkin/backend/chart/FNFLegacyParser.hx +++ b/source/funkin/backend/chart/FNFLegacyParser.hx @@ -109,6 +109,16 @@ class FNFLegacyParser { }); } + if (section.sectionBeats != beatsPerMeasure) { + beatsPerMeasure = section.sectionBeats != null ? section.sectionBeats : data.beatsPerMeasure.getDefault(4); + + result.events.push({ + time: curTime, + name: "Time Signature Change", + params: [section.sectionBeats, 4] + }); + } + curTime += curCrochet * beatsPerMeasure; } } @@ -179,7 +189,8 @@ class FNFLegacyParser { mustHitSection: notes[section-1] != null ? notes[section-1].mustHitSection : false, bpm: notes[section-1] != null ? notes[section-1].bpm : chart.meta.bpm, changeBPM: false, - altAnim: notes[section-1] != null ? notes[section-1].altAnim : false + altAnim: notes[section-1] != null ? notes[section-1].altAnim : false, + sectionBeats: notes[section-1] != null ? notes[section-1].sectionBeats : chart.meta.beatsPerMeasure.getDefault(4) }; var sectionEndTime:Float = Conductor.getTimeForStep(Conductor.getMeasureLength() * (section+1)); @@ -193,6 +204,8 @@ class FNFLegacyParser { case "BPM Change": baseSection.changeBPM = true; baseSection.bpm = event.params[0]; + case "Time Signature Change": + baseSection.sectionBeats = event.params[0]; } } notes[section] = baseSection; diff --git a/source/funkin/backend/system/Conductor.hx b/source/funkin/backend/system/Conductor.hx index bd5fca4c..4af8ab8a 100644 --- a/source/funkin/backend/system/Conductor.hx +++ b/source/funkin/backend/system/Conductor.hx @@ -10,6 +10,8 @@ typedef BPMChangeEvent = var stepTime:Float; var songTime:Float; var bpm:Float; + var beatsPerMeasure:Float; + var stepsPerBeat:Float; } class Conductor @@ -21,6 +23,8 @@ class Conductor public static var onBeatHit:FlxTypedSignalVoid> = new FlxTypedSignal(); public static var onStepHit:FlxTypedSignalVoid> = new FlxTypedSignal(); public static var onBPMChange:FlxTypedSignalVoid> = new FlxTypedSignal(); + public static var onBeatsPerMeasureChange:FlxTypedSignalVoid> = new FlxTypedSignal(); + public static var onStepsPerBeatChange:FlxTypedSignalVoid> = new FlxTypedSignal(); /** * Current BPM @@ -108,45 +112,76 @@ class Conductor songPosition = lastSongPos = curBeatFloat = curStepFloat = curBeat = curStep = 0; bpmChangeMap = []; changeBPM(0); + changeTimeSignature(4, 4); } public static function setupSong(SONG:ChartData) { reset(); mapBPMChanges(SONG); - changeBPM(SONG.meta.bpm, cast SONG.meta.beatsPerMeasure.getDefault(4), cast SONG.meta.stepsPerBeat.getDefault(4)); + changeBPM(SONG.meta.bpm); + changeTimeSignature(cast SONG.meta.beatsPerMeasure.getDefault(4), cast SONG.meta.stepsPerBeat.getDefault(4)); } /** * Maps BPM changes from a song. * @param song Song to map BPM changes from. */ - public static function mapBPMChanges(song:ChartData) - { + public static function mapBPMChanges(song:ChartData) { bpmChangeMap = [ { stepTime: 0, songTime: 0, - bpm: song.meta.bpm + bpm: song.meta.bpm, + beatsPerMeasure: song.meta.beatsPerMeasure.getDefault(4), + stepsPerBeat: song.meta.stepsPerBeat.getDefault(4) } ]; - + if (song.events == null) return; - + var curBPM:Float = song.meta.bpm; + var curBeatsPerMeasure:Float = song.meta.beatsPerMeasure.getDefault(4); + var curStepsPerBeat:Float = song.meta.stepsPerBeat.getDefault(4); var songTime:Float = 0; var stepTime:Float = 0; - - for(e in song.events) if (e.name == "BPM Change" && e.params != null && e.params[0] is Float) { - if (e.params[0] == curBPM) continue; - var steps = (e.time - songTime) / ((60 / curBPM) * 1000 / 4); - stepTime += steps; - songTime = e.time; - curBPM = e.params[0]; - - bpmChangeMap.push({ - stepTime: stepTime, - songTime: songTime, - bpm: curBPM - }); + + for(e in song.events) { + if (e.name == "BPM Change" && e.params != null && e.params[0] is Float) { + if (e.params[0] == curBPM) continue; + var steps = (e.time - songTime) / ((60 / curBPM) * 1000 / stepsPerBeat); + stepTime += steps; + songTime = e.time; + curBPM = e.params[0]; + + bpmChangeMap.push({ + stepTime: stepTime, + songTime: songTime, + bpm: curBPM, + beatsPerMeasure: curBeatsPerMeasure, // keep old beatsPerMeasure and stepsPerMeasure so shit doesnt break + stepsPerBeat: curStepsPerBeat + }); + } + + if (e.name == "Time Signature Change" && e.params != null) { + var newBeatsPerMeasure = e.params[0]; + var newStepsPerBeat = e.params[1]; + + if (newBeatsPerMeasure == curBeatsPerMeasure && newStepsPerBeat == curStepsPerBeat) continue; + + var steps = (e.time - songTime) / ((60 / curBPM) * 1000 / stepsPerBeat); + stepTime += steps; + songTime = e.time; + + curBeatsPerMeasure = newBeatsPerMeasure; + curStepsPerBeat = newStepsPerBeat; + + bpmChangeMap.push({ + stepTime: stepTime, + songTime: songTime, + bpm: curBPM, // keep old bpm so shit doesnt break + beatsPerMeasure: curBeatsPerMeasure, + stepsPerBeat: curStepsPerBeat + }); + } } } @@ -184,22 +219,32 @@ class Conductor if (FlxG.state != null && FlxG.state is MusicBeatState && cast(FlxG.state, MusicBeatState).cancelConductorUpdate) return; __updateSongPos(FlxG.elapsed); - + if (bpm > 0) { - // updates curbeat and stuff + // Check for BPM change __lastChange = { stepTime: 0, songTime: 0, - bpm: 0 + bpm: 0, + beatsPerMeasure: beatsPerMeasure, + stepsPerBeat: stepsPerBeat }; - for (change in Conductor.bpmChangeMap) - { + + for (change in Conductor.bpmChangeMap) { if (Conductor.songPosition >= change.songTime) __lastChange = change; } + + // Change BPM if necessary + if (__lastChange.bpm > 0 && bpm != __lastChange.bpm) { + changeBPM(__lastChange.bpm); + } - if (__lastChange.bpm > 0 && bpm != __lastChange.bpm) changeBPM(__lastChange.bpm); - + // Check for time signature change + if (__lastChange.beatsPerMeasure != beatsPerMeasure || __lastChange.stepsPerBeat != stepsPerBeat) { + changeTimeSignature(__lastChange.beatsPerMeasure, __lastChange.stepsPerBeat); + } + curStepFloat = __lastChange.stepTime + ((Conductor.songPosition - __lastChange.songTime) / Conductor.stepCrochet); curBeatFloat = curStepFloat / stepsPerBeat; curMeasureFloat = curBeatFloat / beatsPerMeasure; @@ -270,34 +315,50 @@ class Conductor onBPMChange.dispatch(bpm); } + + public static function changeTimeSignature(newBeatsPerMeasure:Float, newStepsPerBeat:Float) { + beatsPerMeasure = newBeatsPerMeasure; + stepsPerBeat = newStepsPerBeat; + + crochet = ((60 / bpm) * 1000); + stepCrochet = crochet / stepsPerBeat; + + onBeatsPerMeasureChange.dispatch(beatsPerMeasure); + onStepsPerBeatChange.dispatch(stepsPerBeat); + } public static function getTimeForStep(step:Float) { var bpmChange:BPMChangeEvent = { stepTime: 0, songTime: 0, - bpm: bpm + bpm: bpm, + beatsPerMeasure: beatsPerMeasure, + stepsPerBeat: stepsPerBeat }; for(change in bpmChangeMap) if (change.stepTime < step && change.stepTime >= bpmChange.stepTime) bpmChange = change; - return bpmChange.songTime + ((step - bpmChange.stepTime) * ((60 / bpmChange.bpm) * (1000/stepsPerBeat))); + return bpmChange.songTime + ((step - bpmChange.stepTime) * ((60 / bpmChange.bpm) * (1000 / bpmChange.stepsPerBeat))); } public static function getStepForTime(time:Float) { var bpmChange:BPMChangeEvent = { stepTime: 0, songTime: 0, - bpm: bpm + bpm: bpm, + beatsPerMeasure: beatsPerMeasure, + stepsPerBeat: stepsPerBeat }; - + for(change in bpmChangeMap) if (change.songTime < time && change.songTime >= bpmChange.songTime) bpmChange = change; - - return bpmChange.stepTime + ((time - bpmChange.songTime) / ((60 / bpmChange.bpm) * (1000/stepsPerBeat))); + + return bpmChange.stepTime + ((time - bpmChange.songTime) / ((60 / bpmChange.bpm) * (1000 / bpmChange.stepsPerBeat))); } + public static inline function getMeasureLength() return stepsPerBeat * beatsPerMeasure; diff --git a/source/funkin/editors/charter/CharterEvent.hx b/source/funkin/editors/charter/CharterEvent.hx index 89a5d0d9..b624ee24 100644 --- a/source/funkin/editors/charter/CharterEvent.hx +++ b/source/funkin/editors/charter/CharterEvent.hx @@ -109,7 +109,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable { draggable = true; for (event in events) - if (event.name == "BPM Change") { + if (event.name == "BPM Change" || event.name == "Time Signature Change") { draggable = false; break; } diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index 4e125724..1806fee2 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -1388,6 +1388,7 @@ class PlayState extends MusicBeatState if (strumLines.members[event.params[0]] != null && strumLines.members[event.params[0]].characters != null) for (char in strumLines.members[event.params[0]].characters) if (char != null) char.playAnim(event.params[1], event.params[2], null); + case "Time Signature Change": // automatically handled by conductor case "Unknown": // nothing } }