diff --git a/source/flixel/sound/FlxSound.hx b/source/flixel/sound/FlxSound.hx index 5109ecfa..3edc4e88 100644 --- a/source/flixel/sound/FlxSound.hx +++ b/source/flixel/sound/FlxSound.hx @@ -4,9 +4,6 @@ import lime.media.AudioBuffer; import lime.media.AudioSource; import lime.media.AudioManager; import lime.media.openal.AL; -#if lime_vorbis -import lime.media.vorbis.VorbisFile; -#end import openfl.Assets; import openfl.events.IEventDispatcher; @@ -56,7 +53,7 @@ class FlxSound extends FlxBasic { public var playing(get, never):Bool; /** - * Set volume to a value between 0 and 1 to change how this sound is. + * Set volume to a value between 0 and 1* to change how this sound is. */ public var volume(get, set):Float; @@ -204,6 +201,7 @@ class FlxSound extends FlxBasic { /** * Signal that is dispatched on sound complete. + * Seperates the looping from onComplete. */ public final onFinish:FlxSignal; @@ -225,14 +223,6 @@ class FlxSound extends FlxBasic { */ public var buffer(get, never):AudioBuffer; - #if lime_vorbis - /** - * Stores the sound VorbisFile if exists. - * @since raltyMod - */ - public var vorbis(get, never):VorbisFile; - #end - /** * The tween used to fade this sound's volume in and out (set via `fadeIn()` and `fadeOut()`) * @since 4.1.0 @@ -680,11 +670,11 @@ class FlxSound extends FlxBasic { * the sound and populate the _channel variable. */ var _tries = 0; - function startSound(StartTime:Float) @:privateAccess { + function startSound(startTime:Float) @:privateAccess { if (_sound == null) return; _paused = false; - _time = StartTime; + _time = startTime; _lastTime = FlxG.game.getTicks(); if (_channel == null || !_channel.__isValid || _source.__backend == null || _source.__backend.disposed #if lime_openal || _source.__backend.handle == null #end) makeChannel(); @@ -714,7 +704,7 @@ class FlxSound extends FlxBasic { else { if (++_tries > 2) return; makeChannel(); - return startSound(StartTime); + return startSound(startTime); } _tries = 0; @@ -777,14 +767,14 @@ class FlxSound extends FlxBasic { inline function get_volume():Float return _volume; - inline function set_volume(Volume:Float):Float { - _volume = FlxMath.bound(Volume, 0, 4); + inline function set_volume(v:Float):Float { + _volume = FlxMath.bound(v, 0, 10); updateTransform(); return _volume; } - inline function set_muted(Muted:Bool):Bool { - muted = Muted; + inline function set_muted(v:Bool):Bool { + muted = v; updateTransform(); return muted; } @@ -793,16 +783,11 @@ class FlxSound extends FlxBasic { return buffer != null; inline function get_streamed():Bool - return #if lime_vorbis vorbis != null #else false #end; + @:privateAccess return #if lime_vorbis _sound != null && _sound.__buffer.__srcVorbisFile != null #else false #end; inline function get_buffer():AudioBuffer @:privateAccess return _sound != null ? _sound.__buffer : null; - #if lime_vorbis - inline function get_vorbis():VorbisFile - @:privateAccess return _sound != null ? _sound.__buffer.__srcVorbisFile : null; - #end - function update_amplitude():Void @:privateAccess { if (_channel == null || _time == _amplitudeTime || !_amplitudeUpdate) return; _channel.__updatePeaks(); diff --git a/source/funkin/backend/system/Conductor.hx b/source/funkin/backend/system/Conductor.hx index 7ffcf4d8..2f0621c8 100644 --- a/source/funkin/backend/system/Conductor.hx +++ b/source/funkin/backend/system/Conductor.hx @@ -159,16 +159,9 @@ class Conductor } private static function __updateSongPos(elapsed:Float) { - if (FlxG.sound.music == null || !FlxG.sound.music.playing) { - lastSongPos = FlxG.sound.music != null ? FlxG.sound.music.getActualTime() - songOffset : -songOffset; - return; - } - - if (lastSongPos != (lastSongPos = FlxG.sound.music.getActualTime() - songOffset)) { - // update conductor - songPosition = lastSongPos; - } else { - songPosition += songOffset + elapsed * 1000; + if (FlxG.sound.music != null) { // CNE FlxSound is Interpolated. + lastSongPos = FlxG.sound.music.time - songOffset; + if (FlxG.sound.music.playing) songPosition = FlxG.sound.music.time; } } diff --git a/source/lime/_internal/backend/native/NativeAudioSource.hx b/source/lime/_internal/backend/native/NativeAudioSource.hx index 00a96cee..42bfc72f 100644 --- a/source/lime/_internal/backend/native/NativeAudioSource.hx +++ b/source/lime/_internal/backend/native/NativeAudioSource.hx @@ -1,6 +1,7 @@ // ALL REWRITTEN FROM SCRATCH!!!! -raltyro // YES ALL OF IT!!! // FUCK +// TODO: add a frequency for how much buffers should be regenerated package lime._internal.backend.native; @@ -28,9 +29,10 @@ import lime.utils.ArrayBufferView; @:access(lime.media.AudioBuffer) @:access(lime.utils.ArrayBufferView) class NativeAudioSource { - private static final STREAM_BUFFER_SIZE:Int = 0x4000; - private static final STREAM_MAX_BUFFERS:Int = 16; - private static final STREAM_TIMER_FREQUENCY:Int = 100; + private static var STREAM_BUFFER_SIZE:Int = 0x4000; + private static var STREAM_MAX_BUFFERS:Int = 32; + private static var STREAM_TIMER_FREQUENCY:Int = 100; + private static var STREAM_BUFFER_FREQUENCY:Int = 3; private var parent:AudioSource; private var disposed:Bool; @@ -40,10 +42,11 @@ class NativeAudioSource { private var handle:ALSource; private var buffers:Array; + private var unusedBuffers:Array; private var timer:Timer; private var format:Int; - private var dataLength:Int64; - private var samples:Int64; + private var dataLength:Float; + private var samples:Float; private var streamTimer:Timer; private var bufferDatas:Array; @@ -72,6 +75,9 @@ class NativeAudioSource { if (buffers != null) AL.deleteBuffers(buffers); buffers = null; + bufferDatas = null; + bufferTimes = null; + unusedBuffers = null; } public function init() { @@ -86,15 +92,16 @@ class NativeAudioSource { var vorbisFile = buffer.__srcVorbisFile; if (streamed = vorbisFile != null) { - dataLength = (samples = vorbisFile.pcmTotal()) * buffer.channels * (Int64.ofInt(buffer.bitsPerSample) / 8); + dataLength = (samples = getFloat(vorbisFile.pcmTotal())) * buffer.channels * (buffer.bitsPerSample == 8 ? 1 : 2); var constructor = buffer.bitsPerSample == 8 ? Int8 : Int16; buffers = AL.genBuffers(STREAM_MAX_BUFFERS); bufferDatas = [for (i in 0...STREAM_MAX_BUFFERS) new ArrayBufferView(STREAM_BUFFER_SIZE, constructor)]; bufferTimes = [for (i in 0...STREAM_MAX_BUFFERS) 0]; + unusedBuffers = []; } else { - samples = ((dataLength = buffer.data.length) * 8) / (buffer.channels * buffer.bitsPerSample); + samples = (dataLength = getFloat(Int64.make(0, buffer.data.length))) / buffer.channels / (buffer.bitsPerSample == 8 ? 1 : 2); if (buffer.__srcBuffer == null && (buffer.__srcBuffer = AL.createBuffer()) != null) AL.bufferData(buffer.__srcBuffer, format, buffer.data, buffer.data.length, buffer.sampleRate); @@ -142,62 +149,58 @@ class NativeAudioSource { parent.onComplete.dispatch(); } - inline private function getSamples(ms:Float):Int64 { - var v = Int64.fromFloat(ms / 1000 * parent.buffer.sampleRate); - return v > samples ? samples : (v < 0 ? 0 : v); - } - - inline private function getLengthSamples():Int64 { - return if (length == null) samples; - else Int64.fromFloat((length + parent.offset) / 1000 * parent.buffer.sampleRate); - } - - inline private function getFloat(x:Int64):Float return x.high * 4294967296. + (x.low >>> 0); - - inline private function getRealLength():Float return getFloat(samples) / parent.buffer.sampleRate * 1000; - + // Streaming, atleast for vorbis for now. // just incase if we support more than 1 in the future?? which i doubt - /* private function streamTell():Float { #if lime_vorbis - if (parent.buffer.__srcVorbisFile != null) return parent.buffer.__srcVorbisFile.timeTell(); + /*if (parent.buffer.__srcVorbisFile != null) */return parent.buffer.__srcVorbisFile.timeTell(); #end return 0; } - */ - private function streamTell():Float return #if lime_vorbis parent.buffer.__srcVorbisFile.timeTell() #else 0 #end; private function streamSeek(samples:Int64) { #if lime_vorbis //if (parent.buffer.__srcVorbisFile != null) { // There's apparently a bug in libvorbis <= 1.3.4, hhttps://github.com/xiph/vorbis/blob/master/CHANGES#L39 - if (samples <= 2) parent.buffer.__srcVorbisFile.rawSeek(0); else parent.buffer.__srcVorbisFile.pcmSeek(samples); + // But it seems to also happen in this lime libvorbis version which is 1.3.7...? -ralty + if (samples < 4) parent.buffer.__srcVorbisFile.rawSeek(0); else parent.buffer.__srcVorbisFile.pcmSeek(samples); // break; //} #end } - // Streaming, atleast for vorbis for now. private function readToBufferData(data:ArrayBufferView):Int { var total = 0, result = 0, wordSize:Int = parent.buffer.bitsPerSample == 8 ? 1 : 2; + var pos = streamTell() * parent.buffer.sampleRate * parent.buffer.channels * wordSize; + var n = dataLength - pos < STREAM_BUFFER_SIZE ? Math.floor(dataLength - pos) : STREAM_BUFFER_SIZE; var vorbisFile = parent.buffer.__srcVorbisFile; while (total < STREAM_BUFFER_SIZE) { - result = vorbisFile.read(data.buffer, total, STREAM_BUFFER_SIZE - total, false, wordSize, true); + result = n > 0 ? vorbisFile.read(data.buffer, total, n, false, wordSize, true) : 0; if (result == Vorbis.HOLE) continue; else if (result == Vorbis.EREAD) break; else if (result == 0) { - if (!(streamEnded = (loops <= toLoop))) { + if (!(streamEnded = loops <= toLoop)) { + if (pos < dataLength) continue; toLoop++; - streamSeek(getSamples(loopTime != null ? loopTime : 0)); - } - break; - } - else total += result; - } - if (total < STREAM_BUFFER_SIZE) data.buffer.fill(total, STREAM_BUFFER_SIZE - total - 1, 0); + var samples = getSamples(loopTime != null ? loopTime : 0); + streamSeek(samples); + if (dataLength - (pos = getFloat(samples) * parent.buffer.channels * wordSize) < (n = STREAM_BUFFER_SIZE - total)) + n = Math.floor(dataLength - pos); + } + else + break; + } + else { + pos += result; + total += result; + n -= result; + } + } + + if (total < STREAM_BUFFER_SIZE) data.buffer.fill(total, n, 0); if (result < 0) return result; return total; } @@ -222,28 +225,30 @@ class NativeAudioSource { return decoded; } - private function fillBuffers(buffers:Array) { - for (buffer in buffers) { - if (fillBuffer(buffer) > 0) AL.sourceQueueBuffer(handle, buffer); - if (streamEnded) break; - } - - if (AL.getSourcei(handle, AL.SOURCE_STATE) == AL.STOPPED) { - AL.sourcePlay(handle); - resetTimer((getLength() - getCurrentTime()) / getPitch()); - } - } - private function streamRun() { #if lime_vorbis - if (parent == null || parent.buffer == null || handle == null || buffers == null || parent.buffer.__srcVorbisFile == null) return dispose(); - if (!playing || streamEnded) stopStreamTimer(); + if (parent == null || parent.buffer == null || handle == null) return dispose(); + if (!playing || streamEnded || disposed) stopStreamTimer(); try { - var processed = AL.getSourcei(handle, AL.BUFFERS_PROCESSED); - if (processed > 0) { - fillBuffers(AL.sourceUnqueueBuffers(handle, processed)); - if (queuedBuffers < STREAM_MAX_BUFFERS) fillBuffers([buffers[++requestBuffers - 1]]); + var processed = AL.getSourcei(handle, AL.BUFFERS_PROCESSED), n = STREAM_BUFFER_FREQUENCY, buffer; + + while (processed-- > 0 && !streamEnded) { + buffer = AL.sourceUnqueueBuffer(handle); + if (n-- > 0 && fillBuffer(buffer) > 0) AL.sourceQueueBuffer(handle, buffer); + else unusedBuffers.push(buffer); + } + + if (!streamEnded) { + if (queuedBuffers < STREAM_MAX_BUFFERS) { + if (fillBuffer(buffer = buffers[requestBuffers++]) > 0) AL.sourceQueueBuffer(handle, buffer); + } + else if (unusedBuffers.length != 0 && fillBuffer(buffer = unusedBuffers.pop()) > 0) AL.sourceQueueBuffer(handle, buffer); + } + + if (AL.getSourcei(handle, AL.SOURCE_STATE) == AL.STOPPED) { + AL.sourcePlay(handle); + resetTimer((getLength() - getCurrentTime()) / getPitch()); } } catch(e) trace(e); @@ -255,19 +260,14 @@ class NativeAudioSource { private function resetStreamTimer() { stopStreamTimer(); - - if (streamed) { - streamTimer = new Timer(STREAM_TIMER_FREQUENCY); - streamTimer.run = streamRun; - } + if (streamed) (streamTimer = new Timer(STREAM_TIMER_FREQUENCY)).run = streamRun; } inline function stopTimer() if (timer != null) timer.stop(); private function resetTimer(timeRemaining:Float) { stopTimer(); - timer = new Timer(timeRemaining); - timer.run = timer_onRun; + (timer = new Timer(timeRemaining)).run = timer_onRun; } private function timer_onRun() { @@ -316,8 +316,10 @@ class NativeAudioSource { AL.sourceStop(handle); AL.sourceUnqueueBuffers(handle, AL.getSourcei(handle, AL.BUFFERS_QUEUED)); + unusedBuffers.resize(0); streamSeek(getSamples(value)); - fillBuffers(buffers.slice(0, requestBuffers = queuedBuffers = 3)); + for (i in 0...(requestBuffers = queuedBuffers = STREAM_BUFFER_FREQUENCY)) + if (fillBuffer(buffers[i]) > 0) AL.sourceQueueBuffer(handle, buffers[i]); } else AL.sourcei(handle, AL.SAMPLE_OFFSET, getSamples(value)); @@ -336,18 +338,25 @@ class NativeAudioSource { return value; } + inline private function getRealLength():Float return samples / parent.buffer.sampleRate * 1000; public function getLength():Null { return if (length == null) getRealLength() - parent.offset; else length - parent.offset; } public function setLength(value:Null):Null { - if (value == length) return value; - length = value; + if (value == length || disposed) return length = value; + + var buffer = parent.buffer; + if ((length = value) == null) dataLength = streamed ? samples * buffer.channels * (buffer.bitsPerSample == 8 ? 1 : 2) : getFloat(Int64.make(0, buffer.data.length)); + else dataLength = Math.max(0, Math.min(value, getRealLength())) / 1000 * buffer.sampleRate * buffer.channels * (buffer.bitsPerSample == 8 ? 1 : 2); if (playing) { - var timeRemaining = ((getLength() - parent.offset) - getCurrentTime()) / getPitch(); - if (timeRemaining > 0) resetTimer(timeRemaining); + if (streamed) setCurrentTime(getCurrentTime()); + else { + var timeRemaining = ((getLength() - parent.offset) - getCurrentTime()) / getPitch(); + if (timeRemaining > 0) resetTimer(timeRemaining); + } } return value; } @@ -417,4 +426,7 @@ class NativeAudioSource { } return position; } + + inline private function getFloat(x:Int64):Float return x.high * 4294967296. + (x.low >>> 0); + inline private function getSamples(ms:Float):Int64 return Int64.fromFloat(Math.max(0, Math.min(ms / 1000 * parent.buffer.sampleRate, samples))); } diff --git a/source/openfl/media/SoundChannel.hx b/source/openfl/media/SoundChannel.hx index 7ba37349..bccb6138 100644 --- a/source/openfl/media/SoundChannel.hx +++ b/source/openfl/media/SoundChannel.hx @@ -7,9 +7,9 @@ import openfl.events.Event; import openfl.events.EventDispatcher; #if lime import lime.media.AudioSource; +import lime.media.openal.AL; #if lime_cffi import lime._internal.backend.native.NativeAudioSource; #end -#if lime_vorbis import lime.media.openal.AL; #end #end /** @@ -155,7 +155,6 @@ import lime.media.AudioSource; // took me 8 months to figure this out @:noCompletion inline private static var scanSamples = 480; - #if (lime_cffi && !macro) @:noCompletion private function __checkUpdatePeaks(time:Float):Bool { if (Math.abs(__lastPeakTime - time) < Math.max(1, pitch * 8)) return false; @@ -163,8 +162,7 @@ import lime.media.AudioSource; return true; } - #if lime_vorbis - @:noCompletion private function __updateVorbisPeaks():Void + /*@:noCompletion private function __updateVorbisPeaks():Void { if (__source.buffer == null || !__checkUpdatePeaks(position)) return; @@ -194,14 +192,11 @@ import lime.media.AudioSource; todo--; } } - #end - #end @:noCompletion private function __updatePeaks():Void { __leftPeak = __rightPeak = 0; - #if (lime_cffi && !macro) if (!__isValid) return; #if lime_vorbis if (__source.__backend.streamed) return __updateVorbisPeaks(); #end @@ -230,7 +225,12 @@ import lime.media.AudioSource; } index++; } - #end + }*/ + + @:noCompletion private function __updatePeaks():Void + { + __leftPeak = __rightPeak = 0; + if (!__isValid) return; } @:noCompletion private function __initAudioSource(source:#if lime AudioSource #else Dynamic #end):Void