Stable Reworked Audio
- Reworked Internal Audio to work with Streaming Vorbis Files (for now?) - FlxSound.amplitude, FlxSound.amplitudeLeft, FlxSound.amplitudeRight, SoundChannel.leftPeak, SoundChannel.rightPeak now works. (Streamed Audio on this seems to be half-broken) - Reworked AudioAnalyzer to work with all type of audios (hopefully) and work with Streamed Audio. - Redo AudioSwitchFix to work in time instead of when switching states. gosh, and all that i hope it doesnt break anything.
This commit is contained in:
@@ -16,8 +16,13 @@ import haxe.Timer;
|
||||
class AudioSwitchFix {
|
||||
public static function onAudioDisconnected() @:privateAccess {
|
||||
var soundList:Array<FlxSound> = [FlxG.sound.music];
|
||||
for (sound in FlxG.sound.list) if (sound.playing) soundList.push(sound);
|
||||
for (source in AudioSource.activeSources) source.dispose();
|
||||
for (sound in FlxG.sound.list) if (sound.playing) {
|
||||
sound.pause();
|
||||
soundList.push(sound);
|
||||
}
|
||||
|
||||
var i = AudioSource.activeSources.length;
|
||||
while (i-- > 0) AudioSource.activeSources[i].dispose();
|
||||
|
||||
AudioManager.shutdown();
|
||||
|
||||
@@ -36,7 +41,7 @@ class AudioSwitchFix {
|
||||
// #end
|
||||
|
||||
for (sound in soundList) {
|
||||
sound._paused = true;
|
||||
sound.makeChannel();
|
||||
sound.resume();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,44 +2,121 @@ package funkin.backend.utils;
|
||||
|
||||
import flixel.sound.FlxSound;
|
||||
import lime.media.AudioBuffer;
|
||||
import lime.utils.ArrayBufferView;
|
||||
|
||||
// Thank you yosh :DDD -lunar
|
||||
// (https://github.com/CodenameCrew/YoshiCrafterEngine/blob/main/source/WaveformSprite.hx)
|
||||
#if lime_vorbis
|
||||
import lime.media.vorbis.Vorbis;
|
||||
import lime.media.vorbis.VorbisFile;
|
||||
#end
|
||||
|
||||
// ORIGINAL CODES FROM YOSH & LUNAR https://github.com/CodenameCrew/YoshiCrafterEngine/blob/main/source/WaveformSprite.hx
|
||||
// REWRITTEN BY RALTYRO
|
||||
class AudioAnalyzer {
|
||||
public var buffer:AudioBuffer;
|
||||
var __peakByte:Float = 0;
|
||||
var __timeMulti:Float = 0;
|
||||
var __toBits:Float;
|
||||
var __wordSize:Int;
|
||||
var __bitUnsignedSize:Int;
|
||||
var __bitSize:Int;
|
||||
|
||||
#if lime_vorbis
|
||||
var __vorbis:VorbisFile;
|
||||
#end
|
||||
|
||||
public function new(sound:FlxSound) {
|
||||
@:privateAccess buffer = sound._sound.__buffer;
|
||||
buffer = sound.buffer;
|
||||
|
||||
__peakByte = Math.pow(2, buffer.bitsPerSample-1)-1;
|
||||
__bitUnsignedSize = 1 << buffer.bitsPerSample;
|
||||
__bitSize = 1 << (buffer.bitsPerSample - 1);
|
||||
__toBits = buffer.sampleRate / 1000 * buffer.channels * (__wordSize = buffer.bitsPerSample >> 3);
|
||||
|
||||
__timeMulti = 1 / (1 / buffer.sampleRate);
|
||||
__timeMulti *= buffer.bitsPerSample;
|
||||
__timeMulti -= __timeMulti % buffer.bitsPerSample;
|
||||
#if lime_vorbis
|
||||
__prepareVorbis();
|
||||
#end
|
||||
}
|
||||
|
||||
public function analyze(startPos:Float, endPos:Float):Float {
|
||||
var bytesStartPos:Int = Math.floor(startPos * __timeMulti / 4000 / buffer.bitsPerSample) * buffer.bitsPerSample;
|
||||
var bytesEndPos:Int = Math.floor(endPos * __timeMulti / 4000 / buffer.bitsPerSample) * buffer.bitsPerSample;
|
||||
if (buffer.data != null) return __analyze(startPos, endPos);
|
||||
#if lime_vorbis
|
||||
else if (__prepareVorbis()) return __analyzeVorbis(startPos, endPos);
|
||||
#end
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytesStartPos -= bytesStartPos % buffer.bitsPerSample;
|
||||
bytesEndPos -= bytesEndPos % buffer.bitsPerSample;
|
||||
inline function __analyze(startPos:Float, endPos:Float):Float {
|
||||
var pos = Math.floor(startPos * __toBits), end = Math.floor(endPos * __toBits), buf = #if js buffer.data #else buffer.data.buffer #end;
|
||||
var max = 0, b = 0;
|
||||
if (__wordSize == 1) { // 8-bit audio data is unsigned (0 is 128, 128 is 256, -128 is 0)
|
||||
while (pos < end) {
|
||||
if (max < (b = #if js buf[pos] #else buf.get(pos) #end - __bitSize)) max = b;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pos -= pos % __wordSize;
|
||||
end -= end % __wordSize;
|
||||
|
||||
var maxByte:Int = 0;
|
||||
for(i in 0...Math.floor((bytesEndPos - bytesStartPos) / buffer.bitsPerSample)) {
|
||||
#if js
|
||||
var byte:Int = buffer.data[bytesStartPos + (i * buffer.bitsPerSample)]
|
||||
| (buffer.data[bytesStartPos + (i * buffer.bitsPerSample) + 1] << 8);
|
||||
#else
|
||||
var byte:Int = buffer.data.buffer.get(bytesStartPos + (i * buffer.bitsPerSample))
|
||||
| (buffer.data.buffer.get(bytesStartPos + (i * buffer.bitsPerSample) + 1) << 8);
|
||||
#end
|
||||
if (byte > 256 * 128) byte -= 256 * 256;
|
||||
if (maxByte < byte) maxByte = byte;
|
||||
var w = 0;
|
||||
while (pos < end) {
|
||||
while (w < buffer.bitsPerSample) {
|
||||
b |= #if js buf[pos] #else buf.get(pos) #end << w;
|
||||
w += 8;
|
||||
pos++;
|
||||
}
|
||||
if (b > __bitSize) b -= __bitUnsignedSize;
|
||||
if (max < b) max = b;
|
||||
w = b = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return maxByte/__peakByte;
|
||||
return max / __bitSize;
|
||||
}
|
||||
|
||||
#if lime_vorbis // As far i know, only native supports vorbis
|
||||
var __buffer:ArrayBufferView;
|
||||
function __prepareVorbis():Bool @:privateAccess {
|
||||
if (buffer.__srcVorbisFile == null) return __vorbis != null;
|
||||
if (__vorbis != null) return true;
|
||||
if ((__vorbis = buffer.__srcVorbisFile.clone()) != null) { // IM HOPING IT HAVE A GC CLOSURE.
|
||||
__buffer = new ArrayBufferView(0x1000, buffer.bitsPerSample == 32 ? Int32 : buffer.bitsPerSample == 16 ? Int16 : Int8);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var prevPos:Int = 0;
|
||||
inline function __analyzeVorbis(startPos:Float, endPos:Float):Float {
|
||||
var n = Math.floor((endPos - startPos) * __toBits);
|
||||
if (n < __wordSize) return 0;
|
||||
|
||||
n -= n % __wordSize;
|
||||
|
||||
if (prevPos != Math.floor(startPos)) {
|
||||
__vorbis.timeSeek(startPos / 1000);
|
||||
prevPos = Math.floor(endPos);
|
||||
}
|
||||
|
||||
var isBigEndian = lime.system.System.endianness == lime.system.Endian.BIG_ENDIAN, bufferSize = __buffer.length, buf = __buffer.buffer;
|
||||
var max = 0, b = 0, pos = 0, w = 0, result;
|
||||
while (n > 0) {
|
||||
n -= (result = __vorbis.read(buf, 0, n < bufferSize ? n : bufferSize, isBigEndian, __wordSize, true));
|
||||
|
||||
if (result == Vorbis.HOLE) continue;
|
||||
else if (result <= 0) break;
|
||||
|
||||
while (pos < result) {
|
||||
while (w < buffer.bitsPerSample) {
|
||||
b |= #if js buf[pos] #else buf.get(pos) #end << w;
|
||||
w += 8;
|
||||
pos++;
|
||||
}
|
||||
if (b > __bitSize) b -= __bitUnsignedSize;
|
||||
if (max < b) max = b;
|
||||
w = b = 0;
|
||||
}
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
return max / __bitSize;
|
||||
}
|
||||
#end
|
||||
}
|
||||
@@ -823,7 +823,6 @@ class CoolUtil
|
||||
if (frontEnd.music != null) @:privateAccess frontEnd.destroySound(frontEnd.music);
|
||||
frontEnd.list.remove(music);
|
||||
frontEnd.defaultMusicGroup.add(frontEnd.music = music);
|
||||
music.persist = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1570,10 +1570,10 @@ class Charter extends UIState {
|
||||
vocals.pause();
|
||||
for (strumLine in strumLines.members) strumLine.vocals.pause();
|
||||
} else {
|
||||
FlxG.sound.music.play(Conductor.songPosition + Conductor.songOffset);
|
||||
vocals.play(FlxG.sound.music.getActualTime());
|
||||
FlxG.sound.music.play(true, Conductor.songPosition + Conductor.songOffset);
|
||||
vocals.play(true, FlxG.sound.music.getActualTime());
|
||||
for (strumLine in strumLines.members) {
|
||||
strumLine.vocals.play(FlxG.sound.music.getActualTime());
|
||||
strumLine.vocals.play(true, FlxG.sound.music.getActualTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user