diff --git a/source/funkin/backend/utils/AudioAnalyzer.hx b/source/funkin/backend/utils/AudioAnalyzer.hx index 3f552c55..529aec5d 100644 --- a/source/funkin/backend/utils/AudioAnalyzer.hx +++ b/source/funkin/backend/utils/AudioAnalyzer.hx @@ -38,6 +38,54 @@ class AudioAnalyzer { else return inline ArrayBufferIO.getUint8(buffer, position) - 128; } + /** + * Gets levels from the frequencies with specified sample rate. + * @param frequencies Frequencies input. + * @param sampleRate Sample Rate input. + * @param barCount How much bars to get. + * @param levels The output for getting the values, to avoid memory leaks (Optional). + * @param delta How much delta for smoothen the values from the previous levels values (Optional). + * @param minDb The minimum decibels to cap (Optional, default -70.0). + * @param maxDb The maximum decibels to cap (Optional, default -10.0). + * @param minFreq The minimum frequency to cap (Optional, default 20.0). + * @param maxFreq The maximum frequency to cap (Optional, default 22000.0). + * @return Output of levels/bars + */ + public static function getLevelsFromFrequencies(frequencies:Array, sampleRate:Int, barCount:Int, ?levels:Array, delta = 0.0, minDb = -70.0, maxDb = -10.0, minFreq = 20.0, maxFreq = 22000.0):Array { + if (levels == null) levels = []; + levels.resize(barCount); + + var logMin = Math.log(minFreq), logMax = Math.log(maxFreq); + var logRange = logMax - logMin, dbRange = maxDb - minDb, n = frequencies.length; + inline function calculateScale(i:Int) + return CoolUtil.bound(Math.exp(logMin + (logRange * i / (barCount + 1))) * n * 2 / sampleRate, 0, n - 1); + + var s1 = calculateScale(0), s2; + var i1 = Math.floor(s1), i2; + var v, range; + for (i in 0...barCount) { + if ((range = (s2 = calculateScale(i + 1)) - s1) < 1) { + i2 = Math.ceil(s2); + if (i2 == i1) v = frequencies[i1] * range; + else v = (frequencies[i1] + (frequencies[i2] - frequencies[i1]) * (s1 - i1)) * range; + } + else { + v = frequencies[i1] * (Math.ceil(s1) - i1); + if (i1 != (i2 = Math.floor(s2))) { + while (++i1 < i2) v += frequencies[i1]; + v += frequencies[i2] * (s2 - Math.floor(s2)); + } + } + i1 = Math.floor(s1 = s2); + + v = ((20 * Math.log(v) / 2.302585092994046) - minDb) / dbRange; + if (delta > 0 && delta < 1 && v < levels[i]) levels[i] -= Math.pow(levels[i] - v, 2.302585092994046) * delta; + else levels[i] = v; + } + + return levels; + } + /** * The current sound to analyze. */ @@ -184,42 +232,8 @@ class AudioAnalyzer { * @param maxFreq The maximum frequency to cap (Optional, default 22000.0). * @return Output of levels/bars */ - public function getLevels(startPos:Float, barCount:Int, ?levels:Array, delta = 0.0, minDb = -70.0, maxDb = -10.0, minFreq = 20.0, maxFreq = 22000.0):Array { - __frequencies = getFrequencies(startPos, __frequencies); - - if (levels == null) levels = []; - levels.resize(barCount); - - var logMin = Math.log(minFreq), logMax = Math.log(maxFreq); - var logRange = logMax - logMin, dbRange = maxDb - minDb; - inline function calculateScale(i:Int) - return CoolUtil.bound(Math.exp(logMin + (logRange * i / (barCount + 1))) * fftN / buffer.sampleRate, 0, __N2 - 1); - - var s1 = calculateScale(0), s2; - var i1 = Math.floor(s1), i2; - var v, range; - for (i in 0...barCount) { - if ((range = (s2 = calculateScale(i + 1)) - s1) < 1) { - i2 = Math.ceil(s2); - if (i2 == i1) v = __frequencies[i1] * range; - else v = (__frequencies[i1] + (__frequencies[i2] - __frequencies[i1]) * (s1 - i1)) * range; - } - else { - v = __frequencies[i1] * (Math.ceil(s1) - i1); - if (i1 != (i2 = Math.floor(s2))) { - while (++i1 < i2) v += __frequencies[i1]; - v += __frequencies[i2] * (s2 - Math.floor(s2)); - } - } - i1 = Math.floor(s1 = s2); - - v = ((20 * Math.log(v) / 2.302585092994046) - minDb) / dbRange; - if (delta > 0 && delta < 1 && v < levels[i]) levels[i] -= Math.pow(levels[i] - v, 2) * delta; - else levels[i] = v; - } - - return levels; - } + public function getLevels(startPos:Float, barCount:Int, ?levels:Array, ?delta:Float, ?minDb:Float, ?maxDb:Float, ?minFreq:Float, ?maxFreq:Float):Array + return inline getLevelsFromFrequencies(__frequencies = getFrequencies(startPos, __frequencies), buffer.sampleRate, barCount, levels, delta, minDb, maxDb, minFreq, maxFreq); /** * Gets frequencies from an attached FlxSound from startPos. diff --git a/source/funkin/backend/utils/WindowUtils.hx b/source/funkin/backend/utils/WindowUtils.hx index 706c36e4..4c0c76bf 100644 --- a/source/funkin/backend/utils/WindowUtils.hx +++ b/source/funkin/backend/utils/WindowUtils.hx @@ -63,9 +63,11 @@ final class WindowUtils { * @param image The image to set as the icon. **/ public static inline function setWindow(?name:String, ?image:String) - { - Lib.application.window.setIcon(lime.graphics.Image.fromBytes(Assets.getBytes(Flags.MOD_ICON != null ? Flags.MOD_ICON : image))); - title = Flags.MOD_NAME != null ? Flags.MOD_NAME : title; + { + // Coded by HeroEyad using Pigeon Text Editor v2.03 (E.G.E. Edition) + Lib.application.window.setIcon(lime.graphics.Image.fromBytes(Assets.getBytes(image != null ? image : Flags.MOD_ICON))); + title = name != null ? name : Flags.MOD_NAME; + // End of HeroEyad Code. Coded by HeroEyad. } /** @@ -90,4 +92,4 @@ final class WindowUtils { @:noCompletion private inline static function set_winTitle(value:String):String { return title = value; } -} \ No newline at end of file +} diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx index 445c30bc..10773d51 100644 --- a/source/funkin/editors/charter/Charter.hx +++ b/source/funkin/editors/charter/Charter.hx @@ -633,16 +633,22 @@ class Charter extends UIState { // create events rightEventsGroup.autoSort = leftEventsGroup.autoSort = false; - var __last:CharterEvent = null; - var __lastTime:Float = Math.NaN; - for (e in PlayState.SONG.events) { - if (e == null) continue; - if (__last != null && __lastTime == e.time) { - __last.events.push(e); - } else { - __last = new CharterEvent(Conductor.getStepForTime(e.time), [e]); - __lastTime = e.time; - (__last.global ? rightEventsGroup : leftEventsGroup).add(__last); + var lastLeftEvents:CharterEvent = null, lastRightEvents:CharterEvent = null, lastEvents:CharterEvent; + var lastLeftTime = Math.NaN, lastRightTime = Math.NaN, lastTime:Float; + for (e in PlayState.SONG.events) if (e != null) { + if (e.global) { + lastEvents = lastRightEvents; + lastTime = lastRightTime; + } + else { + lastEvents = lastLeftEvents; + lastTime = lastLeftTime; + } + + if (lastEvents != null && lastTime == e.time) lastEvents.events.push(e); + else { + lastEvents = new CharterEvent(Conductor.getStepForTime(lastTime = e.time), [e], e.global); + (e.global ? rightEventsGroup : leftEventsGroup).add(lastEvents); } } @@ -2278,6 +2284,9 @@ class Charter extends UIState { public function buildEvents() { PlayState.SONG.events = []; + for (ce in leftEventsGroup.members) for (e in ce.events) e.global = false; + for (ce in rightEventsGroup.members) for (e in ce.events) e.global = true; + var events:Array = leftEventsGroup.members.concat(rightEventsGroup.members); events.sort(rightEventsGroup.sortEventsFilter.bind(FlxSort.ASCENDING)); for (e in events) for (event in e.events) { diff --git a/source/funkin/menus/FreeplayState.hx b/source/funkin/menus/FreeplayState.hx index 736f1d6b..7dcb6f3d 100644 --- a/source/funkin/menus/FreeplayState.hx +++ b/source/funkin/menus/FreeplayState.hx @@ -246,24 +246,37 @@ class FreeplayState extends MusicBeatState autoplayElapsed += elapsed; if (!disableAutoPlay && !songInstPlaying && (autoplayElapsed > timeUntilAutoplay || FlxG.keys.justPressed.SPACE)) { if (curPlayingInst != (curPlayingInst = Paths.inst(songs[curSelected].name, songs[curSelected].difficulties[curDifficulty]))) { - var huh:Void->Void = function() { - var soundPath = curPlayingInst; - var sound = null; - if (Assets.exists(soundPath, SOUND) || Assets.exists(soundPath, MUSIC)) - sound = Assets.getSound(soundPath); - else - FlxG.log.error('Could not find a Sound asset with an ID of \'$soundPath\'.'); + var streamed = false; + if (Options.streamedMusic) { + var sound = Assets.getMusic(curPlayingInst, true, false); + streamed = sound != null; - if (sound != null && autoplayShouldPlay) { + if (streamed && autoplayShouldPlay) { FlxG.sound.playMusic(sound, 0); Conductor.changeBPM(songs[curSelected].bpm, songs[curSelected].beatsPerMeasure, songs[curSelected].stepsPerBeat); } } - if (!disableAsyncLoading) Main.execAsync(huh); - else huh(); + + if (!streamed) { + var huh:Void->Void = function() { + var soundPath = curPlayingInst; + var sound = null; + if (Assets.exists(soundPath, SOUND) || Assets.exists(soundPath, MUSIC)) + sound = Assets.getSound(soundPath); + else + FlxG.log.error('Could not find a Sound asset with an ID of \'$soundPath\'.'); + + if (sound != null && autoplayShouldPlay) { + FlxG.sound.playMusic(sound, 0); + Conductor.changeBPM(songs[curSelected].bpm, songs[curSelected].beatsPerMeasure, songs[curSelected].stepsPerBeat); + } + } + if (!disableAsyncLoading) Main.execAsync(huh); + else huh(); + } } songInstPlaying = true; - if(disableAsyncLoading) dontPlaySongThisFrame = true; + if (disableAsyncLoading && !Options.streamedMusic) dontPlaySongThisFrame = true; } #end @@ -423,8 +436,8 @@ class FreeplayState extends MusicBeatState changeDiff(0, true); #if PRELOAD_ALL - autoplayElapsed = 0; - songInstPlaying = false; + autoplayElapsed = 0; + songInstPlaying = false; #end coopText.visible = songs[curSelected].coopAllowed || songs[curSelected].opponentModeAllowed; diff --git a/source/openfl/utils/Assets.hx b/source/openfl/utils/Assets.hx index eef85212..f0c47e83 100644 --- a/source/openfl/utils/Assets.hx +++ b/source/openfl/utils/Assets.hx @@ -241,7 +241,7 @@ class Assets return null; } - public static function getMusic(id:String, useCache:Bool = true):Sound + public static function getMusic(id:String, useCache:Bool = true, staticFallback:Bool = true):Sound { #if (lime_vorbis && lime > "7.9.0" && !macro) if (Options.streamedMusic) { @@ -251,7 +251,7 @@ class Assets if (vorbisFile != null) return Sound.fromAudioBuffer(AudioBuffer.fromVorbisFile(vorbisFile)); } #end - return getSound(id, useCache); + return if (staticFallback) getSound(id, useCache); else null; } /**