diff --git a/source/flixel/sound/FlxSound.hx b/source/flixel/sound/FlxSound.hx index 3edc4e88..ae596dab 100644 --- a/source/flixel/sound/FlxSound.hx +++ b/source/flixel/sound/FlxSound.hx @@ -3,7 +3,6 @@ package flixel.sound; import lime.media.AudioBuffer; import lime.media.AudioSource; import lime.media.AudioManager; -import lime.media.openal.AL; import openfl.Assets; import openfl.events.IEventDispatcher; @@ -283,7 +282,7 @@ class FlxSound extends FlxBasic { _cameras = null; _lastTime = null; _paused = false; - _length = _time = 0; + _offset = _length = _time = 0; _volume = _volumeAdjust = 1; _amplitudeLeft = _amplitudeRight = 0; _amplitudeUpdate = true; @@ -669,20 +668,18 @@ class FlxSound extends FlxBasic { * An internal helper function used to attempt to start playing * the sound and populate the _channel variable. */ - var _tries = 0; function startSound(startTime:Float) @:privateAccess { if (_sound == null) return; _paused = false; _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) + if (_channel == null || !_channel.__isValid || _source.__backend == null #if lime_openal || _source.__backend.disposed || _source.__backend.handle == null #end) makeChannel(); if (_channel != null) { #if FLX_PITCH _timeScaleAdjust = timeScaleBased ? FlxG.timeScale : 1.0; - _realPitch = -1.0; pitch = _pitch; #end @@ -691,24 +688,11 @@ class FlxSound extends FlxBasic { _channel.__leftPeak = 0; _channel.__rightPeak = 0; _channel.addEventListener(Event.SOUND_COMPLETE, stopped); - _source.__backend.playing = true; + + #if lime_openal _source.__backend.playing = true; #end _source.offset = 0; - _source.currentTime = _time; - - #if lime_openal - if (_source.__backend.handle == null) return destroy(); - - var s = false; - try {s = AL.getSourcei(_source.__backend.handle, AL.SOURCE_STATE) == AL.PLAYING;} catch(e) {} - if (s) updateTransform(); - else { - if (++_tries > 2) return; - makeChannel(); - return startSound(startTime); - } - - _tries = 0; - #end + _source.currentTime = startTime - _offset; + #if !lime_openal _source.play(); #end looped = looped; loopTime = loopTime; @@ -730,7 +714,7 @@ class FlxSound extends FlxBasic { if (looped) { cleanup(false); - play(false, loopTime - _offset, endTime - _offset); + play(false, loopTime, endTime); } else cleanup(autoDestroy); } @@ -824,18 +808,9 @@ class FlxSound extends FlxBasic { return _pitch; function set_pitch(v:Float):Float { - var adjusted:Float = FlxMath.bound(v * _timeScaleAdjust, 0); - if (_channel != null && _realPitch != adjusted) { - if ((_channel.pitch = adjusted) > 0 && _realPitch <= 0) { - _realPitch = adjusted; - time = _time; - } - else { - get_time(); - _realPitch = adjusted; - } - } - return _pitch = FlxMath.bound(v, 0); + _realPitch = (_pitch = v) * _timeScaleAdjust; + if (_channel != null) _channel.pitch = _realPitch; + return _pitch; } #end @@ -854,7 +829,7 @@ class FlxSound extends FlxBasic { function set_endTime(v:Null):Null { if (playing) { - if (v != null && v > 0 && v < length) _channel.endTime = v; + if (v != null && v > 0 && v < _length) _channel.endTime = v; else _channel.endTime = null; } return endTime = v; @@ -872,7 +847,7 @@ class FlxSound extends FlxBasic { function get_time():Float { if (_channel == null || AudioManager.context == null) return _time; - final pos = _channel.position - _offset; + final pos = _channel.position + _offset; if (!playing || _realPitch <= 0) { _lastTime = null; return _time = pos; @@ -893,7 +868,7 @@ class FlxSound extends FlxBasic { } function set_time(time:Float):Float @:privateAccess { - time = FlxMath.bound(time, 0, length - 1); + time = FlxMath.bound(time, _offset, length - 1); if (_channel != null && _realPitch > 0) { if (!_channel.__isValid) { cleanup(false, true); @@ -901,7 +876,7 @@ class FlxSound extends FlxBasic { } else if (playing) { _source.offset = 0; - _source.currentTime = time + _offset; + _source.currentTime = time - _offset; } } @@ -909,11 +884,10 @@ class FlxSound extends FlxBasic { return _time = time; } - function get_offset():Float return _offset; - function set_offset(offset:Float):Float { - if (offset == _offset) return offset; - _offset = offset; - time = time; + inline function get_offset():Float return _offset; + inline function set_offset(offset:Float):Float { + if (_offset == (_offset = offset)) return offset; + //time = time - _offset; return offset; } diff --git a/source/lime/_internal/backend/native/NativeAudioSource.hx b/source/lime/_internal/backend/native/NativeAudioSource.hx index ce2d6782..4b187188 100644 --- a/source/lime/_internal/backend/native/NativeAudioSource.hx +++ b/source/lime/_internal/backend/native/NativeAudioSource.hx @@ -29,7 +29,7 @@ class NativeAudioSource { 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 static var STREAM_BUFFER_FREQUENCY:Int = 6; private var parent:AudioSource; private var disposed:Bool; @@ -87,9 +87,8 @@ class NativeAudioSource { if (disposed = (handle = AL.createSource()) == null) return; AL.sourcef(handle, AL.MAX_GAIN, 10); - var vorbisFile = buffer.__srcVorbisFile; - if (streamed = vorbisFile != null) { - dataLength = (samples = getFloat(vorbisFile.pcmTotal())) * buffer.channels * (buffer.bitsPerSample == 8 ? 1 : 2); + if (streamed = buffer.__srcVorbisFile != null) { + dataLength = (samples = getFloat(buffer.__srcVorbisFile.pcmTotal())) * buffer.channels * (buffer.bitsPerSample == 8 ? 1 : 2); var constructor = buffer.bitsPerSample == 8 ? Int8 : Int16; buffers = AL.genBuffers(STREAM_MAX_BUFFERS); @@ -170,22 +169,24 @@ class NativeAudioSource { } private function readToBufferData(data:ArrayBufferView):Int { - var total = 0, result = 0, wordSize = parent.buffer.bitsPerSample == 8 ? 1 : 2, wasEOF = false; + var total = 0, result = 0, wasEOF = false; + var bigEndian = System.endianness == lime.system.Endian.BIG_ENDIAN, wordSize = parent.buffer.bitsPerSample == 8 ? 1 : 2; var size = dataLength - (streamTell() * parent.buffer.sampleRate * parent.buffer.channels * wordSize); var n:Int = size < STREAM_BUFFER_SIZE ? Math.floor(size) : STREAM_BUFFER_SIZE; var vorbisFile = parent.buffer.__srcVorbisFile; while (total < STREAM_BUFFER_SIZE) { - result = n > 0 ? vorbisFile.read(data.buffer, total, n, System.endianness == lime.system.Endian.BIG_ENDIAN, wordSize, true) : 0; + result = n > 0 ? vorbisFile.read(data.buffer, total, n, bigEndian, wordSize, true) : 0; if (result == Vorbis.HOLE) continue; else if (result <= Vorbis.EREAD) break; else if (result == 0) { - if (wasEOF || (streamEnded = loops <= toLoop++)) break; + if (wasEOF || (streamEnded = loops <= toLoop)) break; else { wasEOF = true; + toLoop++; - var samples = getSamples(loopTime != null ? loopTime : 0); + var samples = getSamples(loopTime != null ? loopTime + parent.offset : parent.offset); streamSeek(samples); if ((size = dataLength - (getFloat(samples) * parent.buffer.channels * wordSize)) < (n = STREAM_BUFFER_SIZE - total)) n = Math.floor(size); @@ -194,6 +195,7 @@ class NativeAudioSource { else { total += result; n -= result; + wasEOF = false; } } @@ -205,22 +207,26 @@ class NativeAudioSource { return total; } + private function cycleBuffer() { + var i = STREAM_MAX_BUFFERS - (queuedBuffers = requestBuffers), n = STREAM_MAX_BUFFERS - 1; + var data = bufferDatas[i], time = bufferTimes[i]; + while (i < n) { + bufferDatas[i] = bufferDatas[i + 1]; + bufferTimes[i] = bufferTimes[++i]; + } + bufferDatas[n] = data; + bufferTimes[n] = time; + } + private function fillBuffer(buffer:ALBuffer):Int { - var i = STREAM_MAX_BUFFERS - requestBuffers; - var bufferData = bufferDatas[i], bufferTime = streamTell(); - var decoded = readToBufferData(bufferData); - - if (decoded <= 0) return 0; - AL.bufferData(buffer, format, bufferData, decoded, parent.buffer.sampleRate); + var i = STREAM_MAX_BUFFERS - requestBuffers, time = streamTell(); + var decoded = readToBufferData(bufferDatas[i]); - var n = STREAM_MAX_BUFFERS - 1; - for (x in i...n) { - bufferDatas[x] = bufferDatas[x + 1]; - bufferTimes[x] = bufferTimes[x + 1]; + if (decoded > 0) { + AL.bufferData(buffer, format, bufferDatas[i], decoded, parent.buffer.sampleRate); + bufferTimes[i] = time; + cycleBuffer(); } - queuedBuffers = requestBuffers; - bufferDatas[n] = bufferData; - bufferTimes[n] = bufferTime; return decoded; } @@ -228,25 +234,35 @@ class NativeAudioSource { private function streamRun() { #if lime_vorbis if (parent == null || parent.buffer == null || handle == null) return dispose(); - if (!playing || streamEnded || disposed) stopStreamTimer(); + if (!playing || disposed) stopStreamTimer(); try { - var processed = AL.getSourcei(handle, AL.BUFFERS_PROCESSED), n = STREAM_BUFFER_FREQUENCY * Math.min(1, AL.getSourcef(handle, AL.PITCH)), buffer; + var processed = AL.getSourcei(handle, AL.BUFFERS_PROCESSED), n = STREAM_BUFFER_FREQUENCY, buffer; while (processed-- > 0) { - if (streamEnded || --n < 0) unusedBuffers.push(AL.sourceUnqueueBuffer(handle)); - else if (fillBuffer(buffer = AL.sourceUnqueueBuffer(handle)) > 0) AL.sourceQueueBuffer(handle, buffer); - else unusedBuffers.push(buffer); + buffer = AL.sourceUnqueueBuffer(handle); + if (!streamEnded && --n > 0 && fillBuffer(buffer) > 0) AL.sourceQueueBuffer(handle, buffer); + else { + queuedBuffers = --requestBuffers; + unusedBuffers.push(buffer); + } } if (!streamEnded) { - if (queuedBuffers < STREAM_MAX_BUFFERS) { + if (unusedBuffers.length != 0) { + requestBuffers++; + if (fillBuffer(buffer = unusedBuffers.pop()) > 0) { + queuedBuffers = requestBuffers; + AL.sourceQueueBuffer(handle, buffer); + } + else { + requestBuffers--; + unusedBuffers.push(buffer); + } + } + else if (queuedBuffers < STREAM_MAX_BUFFERS) { if (fillBuffer(buffer = buffers[requestBuffers++]) > 0) AL.sourceQueueBuffer(handle, buffer); else requestBuffers--; } - else if (unusedBuffers.length != 0) { - if (fillBuffer(buffer = unusedBuffers.pop()) > 0) AL.sourceQueueBuffer(handle, buffer); - else unusedBuffers.push(buffer); - } } if (AL.getSourcei(handle, AL.SOURCE_STATE) == AL.STOPPED) { @@ -254,7 +270,7 @@ class NativeAudioSource { resetTimer((getLength() - getCurrentTime()) / getPitch()); } } - catch(e) trace(e); + catch(e) trace('NativeAudioSource Bug! in streamRun $e'); #end } @@ -274,12 +290,10 @@ class NativeAudioSource { } private function timer_onRun() { - if (!streamed || !streamEnded) { - var timeRemaining = (getLength() - getCurrentTime()) / getPitch(); - if (timeRemaining > 30 && AL.getSourcei(handle, AL.SOURCE_STATE) == AL.PLAYING) { - resetTimer(timeRemaining); - return; - } + var timeRemaining = (getLength() - getCurrentTime()) / getPitch(); + if (timeRemaining > 30 && AL.getSourcei(handle, AL.SOURCE_STATE) == AL.PLAYING) { + resetTimer(timeRemaining); + return; } if (loops == 0) { @@ -287,13 +301,15 @@ class NativeAudioSource { return; } - if (toLoop == 0) { + if (toLoop <= 0) { var start = loopTime != null ? loopTime : 0; setLoops(--loops); if (start > 0 || AL.getSourcei(handle, AL.SOURCE_STATE) != AL.PLAYING) setCurrentTime(start); } - else if ((loops -= toLoop) < 0) loops = 0; - toLoop = 0; + else { + if ((loops -= toLoop) < 0) loops = 0; + toLoop = 0; + } parent.onLoop.dispatch(); } @@ -320,22 +336,27 @@ class NativeAudioSource { AL.sourceUnqueueBuffers(handle, AL.getSourcei(handle, AL.BUFFERS_QUEUED)); unusedBuffers.resize(0); - streamSeek(getSamples(value)); - for (i in 0...(requestBuffers = queuedBuffers = STREAM_BUFFER_FREQUENCY)) - if (fillBuffer(buffers[i]) > 0) AL.sourceQueueBuffer(handle, buffers[i]); + streamSeek(getSamples(value + parent.offset)); } else - AL.sourcei(handle, AL.SAMPLE_OFFSET, getSamples(value)); + AL.sourcei(handle, AL.SAMPLE_OFFSET, getSamples(value + parent.offset)); if (playing) { var timeRemaining = (getLength() - value) / AL.getSourcef(handle, AL.PITCH); if (timeRemaining > 0) { - if (AL.getSourcei(handle, AL.SOURCE_STATE) != AL.PLAYING) AL.sourcePlay(handle); - if (streamed) resetStreamTimer(); + if (streamed) { + for (i in 0...(requestBuffers = queuedBuffers = STREAM_BUFFER_FREQUENCY)) + if (fillBuffer(buffers[i]) > 0) AL.sourceQueueBuffer(handle, buffers[i]); + + resetStreamTimer(); + } resetTimer(timeRemaining); + AL.sourcePlay(handle); } - else + else { + stopStreamTimer(); complete(); + } } return value; @@ -372,8 +393,11 @@ class NativeAudioSource { public function setPitch(value:Float):Float { if (disposed || value == AL.getSourcef(handle, AL.PITCH)) return value; if (playing) { - var timeRemaining = (getLength() - getCurrentTime()) / value; - if (timeRemaining > 0) resetTimer(timeRemaining); + if (value <= 0) stopTimer(); + else { + var timeRemaining = (getLength() - getCurrentTime()) / value; + if (timeRemaining > 0) resetTimer(timeRemaining); + } } AL.sourcef(handle, AL.PITCH, value); return value;