diff --git a/source/funkin/Preferences.hx b/source/funkin/Preferences.hx index 60746fea..cbef23bb 100644 --- a/source/funkin/Preferences.hx +++ b/source/funkin/Preferences.hx @@ -61,6 +61,9 @@ class Preferences addPref('gpu-textures', 'gpu textures', true); #end #if desktop + #if lime_vorbis + addPref('song-stream', 'stream songs', false); + #end addPref('preload', 'preload at start', false); #end diff --git a/source/funkin/sound/FlxFunkSound.hx b/source/funkin/sound/FlxFunkSound.hx index 348273ba..e0d5c991 100644 --- a/source/funkin/sound/FlxFunkSound.hx +++ b/source/funkin/sound/FlxFunkSound.hx @@ -1,7 +1,6 @@ package funkin.sound; import openfl.events.Event; -import openfl.net.URLRequest; import openfl.media.SoundMixer; import lime.media.AudioSource; import openfl.media.SoundTransform; @@ -51,20 +50,29 @@ class FlxFunkSound extends FlxBasic super.destroy(); } - public function dispose() { + public function dispose() { source.dispose(); + sound = null; } function set_sound(value:Sound):Sound { + sound = value; if (value != null) { var init:()->Void = () -> { length = value.length; - source.buffer = value.__buffer; - source.init(); + + if (stream) { + source = new AudioSource(value.__buffer); + source.onComplete.add(__soundFinish); + } + else { + source.buffer = value.__buffer; + source.init(); + } + __initMixer(); - source.currentTime = 0; _lastStopTime = 0; if (this.onLoad != null) @@ -85,7 +93,7 @@ class FlxFunkSound extends FlxBasic } } - return sound = value; + return value; } public var onComplete:()->Void; @@ -117,18 +125,8 @@ class FlxFunkSound extends FlxBasic return this; } - public function loadStream(path:String, ?onLoad:()->Void):FlxFunkSound - { - this.onLoad = onLoad; - - if(!path.startsWith("https://")) if (!path.startsWith("./")) - path = './' + (path.contains(':') ? path.split(':').unsafeGet(1) : path); - - final sound = new Sound(); - sound.load(new URLRequest(path)); - this.sound = sound; - return this; - } + public var stream(get, never):Bool; + inline function get_stream() @:privateAccess return #if (desktop && lime_vorbis) source.__backend.stream; #else false; #end public var playing(default, null):Bool = false; public var paused(get, never):Bool; @@ -137,7 +135,7 @@ class FlxFunkSound extends FlxBasic public var length:Float = 0.0; public var time(get, set):Float; inline function get_time() return getTime(); - inline function set_time(value:Float) return source.currentTime = Std.int(value); + inline function set_time(value:Float) return setTime(value); public var pitch(default, set):Float = 1.0; inline function set_pitch(value:Float):Float { @@ -230,7 +228,7 @@ class FlxFunkSound extends FlxBasic var position = source.position; position.x = pan; - position.z = -1 * Math.sqrt(1 - Math.pow(pan, 2)); + position.z = -Math.sqrt(1 - Math.pow(pan, 2)); source.position = position; } @@ -250,4 +248,12 @@ class FlxFunkSound extends FlxBasic return time + FlxG.game.ticks - __lastTick; } + + public function setTime(time:Float):Float { + if (time <= 0) if (stream) + time = 1.0; // hacky fix + + source.currentTime = Std.int(time); + return time; + } } \ No newline at end of file diff --git a/source/funkin/util/Paths.hx b/source/funkin/util/Paths.hx index a39a2bf9..d1774d0e 100644 --- a/source/funkin/util/Paths.hx +++ b/source/funkin/util/Paths.hx @@ -177,7 +177,7 @@ class Paths **/ inline static public function songAudioAssetPath(song:String, asset:String, ?globalAsset:Bool):String { - return getPath('${Song.formatSongFolder(song)}/audio/$asset.$SOUND_EXT', MUSIC, 'songs', globalAsset); + return getPath(Song.formatSongFolder(song) + '/audio/$asset.$SOUND_EXT', MUSIC, 'songs', globalAsset); } inline static public function voicesPath(song:String, ?globalAsset:Bool):String { @@ -202,11 +202,11 @@ class Paths if (!ext.startsWith('/')) ext = '.$ext'; - return getPath('${Song.formatSongFolder(song)}/charts/${diff.toLowerCase()}$ext', TEXT, 'songs'); + return getPath(Song.formatSongFolder(song) + '/charts/${diff.toLowerCase()}$ext', TEXT, 'songs'); } inline static public function songMeta(song:String) { - return getPath('${Song.formatSongFolder(song)}/charts/songMeta.json', TEXT, 'songs'); + return getPath(Song.formatSongFolder(song) + '/charts/songMeta.json', TEXT, 'songs'); } /* diff --git a/source/funkin/util/backend/AssetManager.hx b/source/funkin/util/backend/AssetManager.hx index ce192cd5..8a1dd8b0 100644 --- a/source/funkin/util/backend/AssetManager.hx +++ b/source/funkin/util/backend/AssetManager.hx @@ -1,5 +1,6 @@ package funkin.util.backend; +import lime.media.AudioBuffer; import openfl.media.Sound; import openfl.display3D.textures.TextureBase; import flixel.util.typeLimit.OneOfTwo; @@ -100,9 +101,13 @@ class Asset { #if !web var buffer = sound.__buffer; - if (buffer != null) { - buffer.data.buffer = null; - buffer.data = null; + if (buffer != null) + { + if (buffer.data != null) + { + buffer.data.buffer = null; + buffer.data = null; + } } #end @@ -252,7 +257,7 @@ class AssetManager final cacheImages = (arr:Array) -> { while (arr[0] != null) { - var asset:LoadImage = arr.shift(); + var asset:LoadImage = arr[0]; if (!existsAsset(asset.path)) if (!bitmaps.exists(asset.path)) { var bitmap = __getFileBitmap(asset.path); @@ -261,12 +266,16 @@ class AssetManager lod: asset.lod }); } + + arr.removeAt(0); } } + var stream = Preferences.getPref('song-stream') ?? false; + final cacheSound = (arr:Array, asset:String) -> { if (!existsAsset(asset)) if (!sounds.exists(asset)) { - var sound = __getFileSound(asset); + var sound = stream ? __streamSound(asset) : __getFileSound(asset); sounds.set(asset, sound); } arr.remove(asset); @@ -409,7 +418,7 @@ class AssetManager return graphic; } - public static function getAssetGraphic(key:String):LodGraphic + public static inline function getAssetGraphic(key:String):LodGraphic { return __nullAssetGet(key); } @@ -450,7 +459,7 @@ class AssetManager return sound; } - public static function getAssetSound(key:String):Sound + public static inline function getAssetSound(key:String):Sound { return __nullAssetGet(key); } @@ -460,6 +469,23 @@ class AssetManager return cacheSoundPath(path, staticAsset); } + @:noCompletion + static inline function __streamSound(path:String):Sound { + var sound:Sound = null; + + #if (desktop && lime_vorbis) + var vorbis = lime.media.vorbis.VorbisFile.fromFile(path); + var buffer = AudioBuffer.fromVorbisFile(vorbis); + if (buffer != null) + sound = Sound.fromAudioBuffer(buffer); + #end + + if (sound == null) + sound = __getFileSound(path); + + return sound; + } + @:noCompletion static inline function __getFileSound(path:String):Sound { #if desktop @@ -481,24 +507,27 @@ class AssetManager // Anal Sex - public static inline function setAsset(key:String, asset:Asset, staticAsset:Bool):Void { + public static inline function setAsset(key:String, asset:Asset, staticAsset:Bool):Void + { assetsMap.set(key, asset); staticAsset ? staticAssets.push(key) : tempAssets.push(key); } - public static inline function getAsset(key:String):Asset { + public static inline function getAsset(key:String):Asset + { return assetsMap.get(key); } - public static inline function existsAsset(key:String):Bool { - return getAsset(key) != null; + public static inline function existsAsset(key:String):Bool + { + return assetsMap.exists(key); } - public static inline function disposeAsset(key:String):Bool { - var asset = getAsset(key); - if (asset == null) + public static function disposeAsset(key:String):Bool { + if (!existsAsset(key)) return false; + var asset = getAsset(key); asset.dispose(); assetsMap.remove(key); @@ -509,9 +538,9 @@ class AssetManager } @:noCompletion - inline static function __nullAssetGet(key:String):AssetClass { - var asset = getAsset(key); - return asset != null ? asset.asset : null; + inline static function __nullAssetGet(key:String):AssetClass + { + return existsAsset(key) ? getAsset(key).asset : null; } @:noCompletion diff --git a/source/funkin/util/song/Conductor.hx b/source/funkin/util/song/Conductor.hx index b0c9d12f..388b7a4f 100644 --- a/source/funkin/util/song/Conductor.hx +++ b/source/funkin/util/song/Conductor.hx @@ -74,10 +74,13 @@ class Conductor vocals.loadSound(Paths.voices(song)); // Reload song file on dispose - AssetManager.getAsset(Paths.instPath(song)).onDispose = () -> { - inst.dispose(); - vocals.dispose(); - loadedSong = ""; + var asset = AssetManager.getAsset(Paths.instPath(song)); + if (asset != null) { + asset.onDispose = () -> { + inst.dispose(); + vocals.dispose(); + loadedSong = ""; + } } } loadedSong = song; @@ -190,7 +193,7 @@ class Conductor } } - public static function sync():Void { + public static function sync():Void { soundSync(inst, offset[0]); if (hasVocals) soundSync(vocals, offset[1]); }