From 8bc4f050fca4734ee9519f9c2787559661c07617 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 13 Apr 2025 21:07:37 +0200 Subject: [PATCH 1/5] fix(android): Ensure bravura and sonivox assets --- src.kotlin/alphaTab/android/build.gradle.kts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src.kotlin/alphaTab/android/build.gradle.kts b/src.kotlin/alphaTab/android/build.gradle.kts index 093569055..c56fd5636 100644 --- a/src.kotlin/alphaTab/android/build.gradle.kts +++ b/src.kotlin/alphaTab/android/build.gradle.kts @@ -102,12 +102,29 @@ android { getByName("main") { java.srcDirs("../../../dist/lib.kotlin/commonMain/generated") kotlin.srcDirs("../../../dist/lib.kotlin/commonMain/generated") + assets.srcDirs( + "../../../font/bravura", + "../../../font/sonivox" + ) } getByName("test") { java.srcDirs("../../../dist/lib.kotlin/commonTest/generated") kotlin.srcDirs("../../../dist/lib.kotlin/commonTest/generated") } } + + androidResources { + ignoreAssetsPattern = arrayOf( + "eot", + "ttf", + "svg", + "woff", + "woff2", + "json", + "txt", + "md" + ).joinToString(":") { "!*.${it}" } + } } dependencies { From 6656c1564d15f725d80b2f6ce589f53a0856d9bc Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 13 Apr 2025 21:08:02 +0200 Subject: [PATCH 2/5] build(android): Ensure signed maven publications --- src.kotlin/alphaTab/android/build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src.kotlin/alphaTab/android/build.gradle.kts b/src.kotlin/alphaTab/android/build.gradle.kts index c56fd5636..dba7b95a9 100644 --- a/src.kotlin/alphaTab/android/build.gradle.kts +++ b/src.kotlin/alphaTab/android/build.gradle.kts @@ -155,6 +155,8 @@ mavenPublishing { publishJavadocJar = true )) + signAllPublications() + pom { name = libArtifactId description = libDescription From ec636ebac04dce84418e868c4d0c3acece709512 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 13 Apr 2025 21:08:59 +0200 Subject: [PATCH 3/5] build(android): Use released maven publish plugin --- src.kotlin/alphaTab/gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src.kotlin/alphaTab/gradle/libs.versions.toml b/src.kotlin/alphaTab/gradle/libs.versions.toml index 3486f4310..423cc05fa 100644 --- a/src.kotlin/alphaTab/gradle/libs.versions.toml +++ b/src.kotlin/alphaTab/gradle/libs.versions.toml @@ -12,7 +12,7 @@ coreKtx = "1.15.0" junit = "4.13.2" junitVersion = "1.2.1" alphaskia = "2.3.120" -mavenPublish = "0.31.1-SNAPSHOT" +mavenPublish = "0.31.0" [libraries] From e3f100bee85e90aff1cef02a8df4a89b2aad0272 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 13 Apr 2025 21:43:01 +0200 Subject: [PATCH 4/5] build(android): Local Maven Publishing for tests --- src.kotlin/alphaTab/android/build.gradle.kts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src.kotlin/alphaTab/android/build.gradle.kts b/src.kotlin/alphaTab/android/build.gradle.kts index dba7b95a9..13978e2fa 100644 --- a/src.kotlin/alphaTab/android/build.gradle.kts +++ b/src.kotlin/alphaTab/android/build.gradle.kts @@ -144,6 +144,17 @@ dependencies { testImplementation(libs.kotlinx.coroutines.test) } +publishing { + repositories{ + maven { + name = "DistPath" + url = rootProject.projectDir.resolve("dist").toURI() + } + } +} + +internal fun Project.findOptionalProperty(propertyName: String) = findProperty(propertyName)?.toString() + mavenPublishing { publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL, automaticRelease = true) coordinates(libGroup, libArtifactId, libVersion) @@ -155,7 +166,14 @@ mavenPublishing { publishJavadocJar = true )) - signAllPublications() + val inMemoryKeyFile = project.findOptionalProperty("signingInMemoryKeyFile") + if (inMemoryKeyFile != null) { + val inMemoryKeyId = project.findOptionalProperty("signingInMemoryKeyId") + val inMemoryKeyPassword = project.findOptionalProperty("signingInMemoryKeyPassword").orEmpty() + val signing = project.extensions.getByType(SigningExtension::class.java) + val inMemoryKey = File(inMemoryKeyFile).readText() + signing.useInMemoryPgpKeys(inMemoryKeyId, inMemoryKey, inMemoryKeyPassword) + } pom { name = libArtifactId From 1d95d26fa7b3df92fe2556c52729e1891c66c808 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 13 Apr 2025 22:30:56 +0200 Subject: [PATCH 5/5] fix: Incosistent sample decoding across platforms --- src.csharp/AlphaTab.Test/TestPlatform.cs | 2 +- src.csharp/AlphaTab/Core/Dom/TextDecoder.cs | 4 +- .../AlphaTab/Core/EcmaScript/ArrayBuffer.cs | 16 +-- .../AlphaTab/Core/EcmaScript/DataView.cs | 125 +++--------------- .../AlphaTab/Core/EcmaScript/Int16Array.cs | 54 +------- .../AlphaTab/Core/EcmaScript/Uint8Array.cs | 74 +++++------ src.csharp/AlphaTab/Io/TypeConversions.cs | 30 ++++- .../Skia/AlphaSkiaBridge/AlphaSkiaBridge.cs | 10 +- .../java/alphaTab/core/ecmaScript/DataView.kt | 47 ++++++- .../alphaTab/core/ecmaScript/Float32Array.kt | 2 +- .../alphaTab/core/ecmaScript/Int16Array.kt | 34 +---- .../alphaTab/core/ecmaScript/Int32Array.kt | 10 +- .../alphaTab/core/ecmaScript/Uint8Array.kt | 13 +- .../platform/android/AndroidAudioWorker.kt | 2 +- src/synth/soundfont/Hydra.ts | 8 +- 15 files changed, 168 insertions(+), 263 deletions(-) diff --git a/src.csharp/AlphaTab.Test/TestPlatform.cs b/src.csharp/AlphaTab.Test/TestPlatform.cs index 89065cf91..db8ae5914 100644 --- a/src.csharp/AlphaTab.Test/TestPlatform.cs +++ b/src.csharp/AlphaTab.Test/TestPlatform.cs @@ -48,7 +48,7 @@ public static async Task SaveFile(string name, Uint8Array data) var path = Path.Combine(RepositoryRoot.Value, name); Directory.CreateDirectory(Path.GetDirectoryName(path)!); await using var fs = new FileStream(path, FileMode.Create); - await fs.WriteAsync(data.Data.Array!, data.Data.Offset, data.Data.Count); + await fs.WriteAsync(data.Buffer.Raw, (int)data.ByteOffset, (int)data.Length); } public static Task> ListDirectory(string path) diff --git a/src.csharp/AlphaTab/Core/Dom/TextDecoder.cs b/src.csharp/AlphaTab/Core/Dom/TextDecoder.cs index 37619d078..b930ba788 100644 --- a/src.csharp/AlphaTab/Core/Dom/TextDecoder.cs +++ b/src.csharp/AlphaTab/Core/Dom/TextDecoder.cs @@ -13,6 +13,6 @@ public TextDecoder(string encoding) public string Decode(ArrayBuffer data) { - return _encoding.GetString(data.Raw.Array, data.Raw.Offset, data.Raw.Count); + return _encoding.GetString(data.Raw, 0, (int)data.ByteLength); } -} \ No newline at end of file +} diff --git a/src.csharp/AlphaTab/Core/EcmaScript/ArrayBuffer.cs b/src.csharp/AlphaTab/Core/EcmaScript/ArrayBuffer.cs index d3b03b12e..db719aab2 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/ArrayBuffer.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/ArrayBuffer.cs @@ -1,22 +1,16 @@ -using System; - -namespace AlphaTab.Core.EcmaScript; +namespace AlphaTab.Core.EcmaScript; public class ArrayBuffer { - public ArraySegment Raw { get; } - public double ByteLength => Raw.Count; + public byte[] Raw { get; } + public double ByteLength => Raw.Length; public ArrayBuffer(double size) { - Raw = new ArraySegment(new byte[(int) size]); + Raw = new byte[(int) size]; } public ArrayBuffer(byte[] raw) - { - Raw = new ArraySegment(raw, 0, raw.Length); - } - public ArrayBuffer(ArraySegment raw) { Raw = raw; } -} \ No newline at end of file +} diff --git a/src.csharp/AlphaTab/Core/EcmaScript/DataView.cs b/src.csharp/AlphaTab/Core/EcmaScript/DataView.cs index 9f5325e49..d4a3d8e46 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/DataView.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/DataView.cs @@ -5,138 +5,47 @@ namespace AlphaTab.Core.EcmaScript; internal class DataView { public ArrayBuffer Buffer { get; } + public double ByteOffset { get; } + public double ByteLength { get; } + public DataView(ArrayBuffer buffer) { Buffer = buffer; } - public double GetUint8(double offset) + public DataView(ArrayBuffer buffer, double byteOffset, double byteLength) { - return Buffer.Raw.Array![Buffer.Raw.Offset + (int) offset]; + Buffer = buffer; + ByteOffset = byteOffset; + ByteLength = byteLength; } - public void SetUint16(double offset, double value, bool littleEndian) + public double GetInt16(double offset, bool littleEndian) { - var bytes = BitConverter.GetBytes((ushort) value); - if (littleEndian != BitConverter.IsLittleEndian) + if (littleEndian == BitConverter.IsLittleEndian) { - System.Array.Reverse(bytes); + return BitConverter.ToInt16(Buffer.Raw, (int)(ByteOffset + offset)); } - System.Buffer.BlockCopy(bytes, 0, Buffer.Raw.Array!, Buffer.Raw.Offset + (int) offset, - bytes.Length); - } - - public double GetInt16(double offset, bool littleEndian) - { var bytes = new byte[sizeof(short)]; - System.Buffer.BlockCopy(Buffer.Raw.Array!, Buffer.Raw.Offset + (int) offset, bytes, 0, + System.Buffer.BlockCopy(Buffer.Raw, (int)(ByteOffset + offset), bytes, 0, bytes.Length); - if (littleEndian != BitConverter.IsLittleEndian) - { - System.Array.Reverse(bytes); - } - + System.Array.Reverse(bytes); return BitConverter.ToInt16(bytes, 0); } - public void SetInt16(double offset, double value, bool littleEndian) - { - var bytes = BitConverter.GetBytes((short) value); - if (littleEndian != BitConverter.IsLittleEndian) - { - System.Array.Reverse(bytes); - } - - System.Buffer.BlockCopy(bytes, 0, Buffer.Raw.Array!, Buffer.Raw.Offset + (int) offset, - bytes.Length); - } - - public double GetUint32(double offset, bool littleEndian) - { - var bytes = new byte[sizeof(uint)]; - System.Buffer.BlockCopy(Buffer.Raw.Array!, Buffer.Raw.Offset + (int) offset, bytes, 0, - bytes.Length); - if (littleEndian != BitConverter.IsLittleEndian) - { - System.Array.Reverse(bytes); - } - - return BitConverter.ToUInt32(bytes, 0); - } - - public double GetInt32(double offset, bool littleEndian) - { - var bytes = new byte[sizeof(uint)]; - System.Buffer.BlockCopy(Buffer.Raw.Array!, Buffer.Raw.Offset + (int) offset, bytes, 0, - bytes.Length); - if (littleEndian != BitConverter.IsLittleEndian) - { - System.Array.Reverse(bytes); - } - - return BitConverter.ToInt32(bytes, 0); - } - - public void SetInt32(double offset, double value, bool littleEndian) - { - var bytes = BitConverter.GetBytes((int) value); - if (littleEndian != BitConverter.IsLittleEndian) - { - System.Array.Reverse(bytes); - } - - System.Buffer.BlockCopy(bytes, 0, Buffer.Raw.Array!, Buffer.Raw.Offset + (int) offset, bytes - .Length); - } - - public double GetUint16(double offset, bool littleEndian) + public double GetFloat32(double offset, bool littleEndian = true) { - var bytes = new byte[sizeof(ushort)]; - System.Buffer.BlockCopy(Buffer.Raw.Array!, Buffer.Raw.Offset + (int) offset, bytes, 0, - bytes.Length); - if (littleEndian != BitConverter.IsLittleEndian) + if (littleEndian == BitConverter.IsLittleEndian) { - System.Array.Reverse(bytes); + return BitConverter.ToSingle(Buffer.Raw, (int)(ByteOffset + offset)); } - return BitConverter.ToUInt16(bytes, 0); - } - - public double GetFloat32(double offset, bool littleEndian = true) - { var bytes = new byte[sizeof(float)]; - System.Buffer.BlockCopy(Buffer.Raw.Array!, Buffer.Raw.Offset + (int) offset, bytes, 0, + System.Buffer.BlockCopy(Buffer.Raw, (int)(ByteOffset + offset), bytes, 0, bytes.Length); - if (littleEndian != BitConverter.IsLittleEndian) - { - System.Array.Reverse(bytes); - } - + System.Array.Reverse(bytes); return BitConverter.ToSingle(bytes, 0); } - - public void SetUint8(double offset, double value) - { - Buffer.Raw.Array![Buffer.Raw.Offset + (int) offset] = (byte) value; - } - - public double GetInt8(double offset) - { - return (sbyte) Buffer.Raw.Array![Buffer.Raw.Offset + (int) offset]; - } - - public double SetUint32(double offset, double value, bool littleEndian) - { - var bytes = BitConverter.GetBytes((uint)value); - if (littleEndian != BitConverter.IsLittleEndian) - { - System.Array.Reverse(bytes); - } - - System.Buffer.BlockCopy(bytes, 0, Buffer.Raw.Array!, Buffer.Raw.Offset + (int) offset, bytes - .Length); - return value; - } } diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Int16Array.cs b/src.csharp/AlphaTab/Core/EcmaScript/Int16Array.cs index 4cb7de2b0..0a018555f 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/Int16Array.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/Int16Array.cs @@ -1,72 +1,30 @@ -using System; -using System.Collections; +using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; namespace AlphaTab.Core.EcmaScript; internal class Int16Array : IEnumerable { - private readonly short[]? _data; - private readonly ArrayBuffer? _buffer; + private readonly short[] _data; - public double Length => _data?.Length ?? _buffer.ByteLength / 2; + public double Length => _data.Length; public Int16Array(double size) { _data = new short[(int)size]; } - internal Int16Array(ArrayBuffer buffer) - { - _buffer = buffer; - } - public double this[double index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return _data != null - ? _data[(int)index] - : GetInt16FromBuffer(index); - } + get => _data[(int)index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - if (_data != null) - { - _data[(int)index] = (short)value; - } - else - { - var bytes = BitConverter.GetBytes(value); - - Buffer.BlockCopy(bytes, - 0, _buffer.Raw.Array!, - (_buffer.Raw.Offset + ((int)index * sizeof(short))), - bytes.Length * sizeof(short) - ); - } - } - } - - private short GetInt16FromBuffer(double index) - { - return BitConverter.ToInt16(_buffer.Raw.Array!, - _buffer.Raw.Offset + ((int)index * sizeof(short))); + set => _data[(int)index] = (short)value; } public IEnumerator GetEnumerator() { - if (_data == null) - { - return Enumerable.Range(0, (int)Length) - .Select(i => GetInt16FromBuffer(i)) - .GetEnumerator(); - } - return ((IEnumerable)_data).GetEnumerator(); } @@ -74,4 +32,4 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } -} \ No newline at end of file +} diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Uint8Array.cs b/src.csharp/AlphaTab/Core/EcmaScript/Uint8Array.cs index 31e90ffc4..96221bd05 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/Uint8Array.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/Uint8Array.cs @@ -1,4 +1,3 @@ -using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -8,42 +7,33 @@ namespace AlphaTab.Core.EcmaScript; public class Uint8Array : IEnumerable, IEnumerable { - private ArraySegment _data; + public double Length { get; } + public double ByteOffset { get; } - public double Length => _data.Count; - public double ByteOffset => _data.Offset; + public ArrayBuffer Buffer { get; } - internal ArrayBuffer Buffer => new ArrayBuffer(_data); - - public ArraySegment Data => _data; - - internal Uint8Array(IList data) - { - _data = new ArraySegment(data.Select(d => (byte)d).ToArray()); - } - - internal Uint8Array(ArrayBuffer buffer) + internal Uint8Array(ArrayBuffer buffer) : this(buffer, 0, buffer.Raw.Length) { - _data = buffer.Raw; } public Uint8Array() : this(System.Array.Empty()) { } - public Uint8Array(byte[] data) + public Uint8Array(byte[] data) : this(new ArrayBuffer(data)) { - _data = new ArraySegment(data); } - private Uint8Array(ArraySegment data) + public Uint8Array(double size) + : this(new byte[(int)size]) { - _data = data; } - public Uint8Array(double size) - : this(new byte[(int)size]) + private Uint8Array(ArrayBuffer buffer, double byteOffset, double byteLength) { + Buffer = buffer; + ByteOffset = byteOffset; + Length = byteLength; } public Uint8Array(IEnumerable values) @@ -54,22 +44,24 @@ public Uint8Array(IEnumerable values) public double this[double index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _data.Array![_data.Offset + (int)index]; + get => Buffer.Raw[(int)ByteOffset + (int)index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => _data.Array![_data.Offset + (int)index] = (byte)value; + set => Buffer.Raw[(int)ByteOffset + (int)index] = (byte)value; } public Uint8Array Subarray(double begin, double end) { - return new Uint8Array(new ArraySegment(_data.Array!, _data.Offset + (int)begin, - (int)(end - begin))); + return new Uint8Array(Buffer, + ByteOffset + begin, + (int)(end - begin) + ); } public void Set(Uint8Array subarray, double pos) { var buffer = subarray.Buffer.Raw; - System.Buffer.BlockCopy(buffer.Array!, buffer.Offset, _data.Array!, - _data.Offset + (int)pos, buffer.Count); + System.Buffer.BlockCopy(buffer, (int)subarray.ByteOffset, Buffer.Raw, + (int)(ByteOffset + pos), (int)subarray.Length); } public static implicit operator Uint8Array(byte[] v) @@ -79,12 +71,18 @@ public static implicit operator Uint8Array(byte[] v) IEnumerator IEnumerable.GetEnumerator() { - return _data.Select(d => (double)d).GetEnumerator(); + for (var i = 0; i < Length; i++) + { + yield return this[i]; + } } public IEnumerator GetEnumerator() { - return ((IEnumerable)_data).GetEnumerator(); + for (var i = 0; i < Length; i++) + { + yield return Buffer.Raw[(int)(ByteOffset + i)]; + } } IEnumerator IEnumerable.GetEnumerator() @@ -94,19 +92,19 @@ IEnumerator IEnumerable.GetEnumerator() public Uint8Array Slice(double startByte, double endByte) { - return new Uint8Array(new ArraySegment( - _data.Array!, - _data.Offset + (int)startByte, - (int)endByte - (int)startByte - )); + return new Uint8Array( + Buffer, + ByteOffset + startByte, + endByte - startByte + ); } public void Reverse() { System.Array.Reverse( - _data.Array!, - _data.Offset, - _data.Count + Buffer.Raw, + (int)ByteOffset, + (int)Length ); } -} \ No newline at end of file +} diff --git a/src.csharp/AlphaTab/Io/TypeConversions.cs b/src.csharp/AlphaTab/Io/TypeConversions.cs index cbec04a4d..faee7026b 100644 --- a/src.csharp/AlphaTab/Io/TypeConversions.cs +++ b/src.csharp/AlphaTab/Io/TypeConversions.cs @@ -6,7 +6,14 @@ internal static class TypeConversions { public static double BytesToFloat32LE(Uint8Array array) { - return BitConverter.ToSingle(array.Data.Array!, array.Data.Offset); + if (!BitConverter.IsLittleEndian) + { + // not optimal but we know the only usage is in IOHelper + // where an own dedicated array is passed-in + System.Array.Reverse(array.Buffer.Raw, (int)array.ByteOffset, (int)array.Length); + } + + return BitConverter.ToSingle(array.Buffer.Raw, (int)array.ByteOffset); } public static Uint8Array Float32BEToBytes(double v) @@ -21,7 +28,14 @@ public static Uint8Array Float32BEToBytes(double v) public static double BytesToFloat64LE(Uint8Array array) { - return BitConverter.ToDouble(array.Data.Array!, array.Data.Offset); + if (!BitConverter.IsLittleEndian) + { + // not optimal but we know the only usage is in IOHelper + // where an own dedicated array is passed-in + System.Array.Reverse(array.Buffer.Raw, (int)array.ByteOffset, (int)array.Length); + } + + return BitConverter.ToDouble(array.Buffer.Raw, (int)array.ByteOffset); } public static double Int32ToUint16(double v) @@ -51,7 +65,13 @@ public static double Int16ToUint32(double v) public static double BytesToInt64LE(Uint8Array array) { - return BitConverter.ToInt64(array.Buffer.Raw.Array!, - array.Buffer.Raw.Offset + (int)array.ByteOffset); + if (!BitConverter.IsLittleEndian) + { + // not optimal but we know the only usage is in IOHelper + // where an own dedicated array is passed-in + System.Array.Reverse(array.Buffer.Raw, (int)array.ByteOffset, (int)array.Length); + } + + return BitConverter.ToInt64(array.Buffer.Raw, (int)array.ByteOffset); } -} \ No newline at end of file +} diff --git a/src.csharp/AlphaTab/Platform/Skia/AlphaSkiaBridge/AlphaSkiaBridge.cs b/src.csharp/AlphaTab/Platform/Skia/AlphaSkiaBridge/AlphaSkiaBridge.cs index 5e7607183..029d64f99 100644 --- a/src.csharp/AlphaTab/Platform/Skia/AlphaSkiaBridge/AlphaSkiaBridge.cs +++ b/src.csharp/AlphaTab/Platform/Skia/AlphaSkiaBridge/AlphaSkiaBridge.cs @@ -48,7 +48,7 @@ public void Dispose() return null; } - return new ArrayBuffer(new ArraySegment(data, 0, data.Length)); + return new ArrayBuffer(data); } internal ArrayBuffer? ToPng() @@ -59,19 +59,19 @@ public void Dispose() return null; } - return new ArrayBuffer(new ArraySegment(data, 0, data.Length)); + return new ArrayBuffer(data); } internal static AlphaSkiaImage? Decode(ArrayBuffer buffer) { - var underlying = AlphaSkia.AlphaSkiaImage.Decode(buffer.Raw.Array!); + var underlying = AlphaSkia.AlphaSkiaImage.Decode(buffer.Raw); return underlying == null ? null : new AlphaSkiaImage(underlying); } internal static AlphaSkiaImage? FromPixels(double width, double height, ArrayBuffer pixels) { var underlying = - AlphaSkia.AlphaSkiaImage.FromPixels((int)width, (int)height, pixels.Raw.Array!); + AlphaSkia.AlphaSkiaImage.FromPixels((int)width, (int)height, pixels.Raw); return underlying == null ? null : new AlphaSkiaImage(underlying); } } @@ -258,7 +258,7 @@ public void Dispose() [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AlphaSkiaTypeface? Register(ArrayBuffer buffer) { - var underlying = AlphaSkia.AlphaSkiaTypeface.Register(buffer.Raw.Array!); + var underlying = AlphaSkia.AlphaSkiaTypeface.Register(buffer.Raw); return underlying == null ? null : new AlphaSkiaTypeface(underlying); diff --git a/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/DataView.kt b/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/DataView.kt index 7e1cbce10..c42c8fb81 100644 --- a/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/DataView.kt +++ b/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/DataView.kt @@ -3,14 +3,51 @@ package alphaTab.core.ecmaScript import java.nio.ByteOrder @ExperimentalUnsignedTypes -internal class DataView(val buffer: ArrayBuffer) { - private val _bufferView = java.nio.ByteBuffer.wrap(buffer.asByteArray()).order(ByteOrder.LITTLE_ENDIAN) +internal class DataView { + private val _littleEndianBufferView: java.nio.ByteBuffer + private val _bigEndianBufferView: java.nio.ByteBuffer + + val buffer: ArrayBuffer + val byteOffset: Double + val byteLength: Double + + constructor(buffer: ArrayBuffer) { + this.buffer = buffer + byteOffset = 0.0 + byteLength = buffer.size.toDouble() + this._littleEndianBufferView = + java.nio.ByteBuffer.wrap(buffer.asByteArray()).order(ByteOrder.LITTLE_ENDIAN) + this._bigEndianBufferView = + java.nio.ByteBuffer.wrap(buffer.asByteArray()).order(ByteOrder.BIG_ENDIAN) + + } + + constructor(buffer: ArrayBuffer, byteOffset: Double, byteLength: Double) { + this.buffer = buffer + this.byteOffset = byteOffset + this.byteLength = byteLength + this._littleEndianBufferView = + java.nio.ByteBuffer.wrap(buffer.asByteArray(), byteOffset.toInt(), byteLength.toInt()) + .order(ByteOrder.LITTLE_ENDIAN) + this._bigEndianBufferView = + java.nio.ByteBuffer.wrap(buffer.asByteArray(), byteOffset.toInt(), byteLength.toInt()) + .order(ByteOrder.BIG_ENDIAN) + } fun getFloat32(index: Double, littleEndian: Boolean): Double { return if (littleEndian) { - _bufferView.getFloat(index.toInt()).toDouble() + _littleEndianBufferView + } else { + _bigEndianBufferView + }.getFloat((byteOffset + index).toInt()).toDouble() + } + + + fun getInt16(index: Double, littleEndian: Boolean): Double { + return if (littleEndian) { + _littleEndianBufferView } else { - _bufferView.order(ByteOrder.BIG_ENDIAN).getFloat(index.toInt()).toDouble() - } + _bigEndianBufferView + }.getShort((byteOffset + index).toInt()).toDouble() } } diff --git a/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Float32Array.kt b/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Float32Array.kt index 200030b68..1dc784a46 100644 --- a/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Float32Array.kt +++ b/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Float32Array.kt @@ -43,7 +43,7 @@ public class Float32Array : Iterable { data[idx] = value.toFloat() } - override fun iterator(): Iterator { + override fun iterator(): FloatIterator { return data.iterator() } diff --git a/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Int16Array.kt b/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Int16Array.kt index 4ccd7690d..57d05fe2b 100644 --- a/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Int16Array.kt +++ b/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Int16Array.kt @@ -5,56 +5,32 @@ import alphaTab.core.byteLength @Suppress("NOTHING_TO_INLINE") @ExperimentalUnsignedTypes internal class Int16Array : Iterable { - private val _data: ShortArray? - private val _buffer: ArrayBuffer? - private val _byteBuffer: java.nio.ByteBuffer? + private val _data: ShortArray public val length: Double - get() { - return _data?.size?.toDouble() ?: (_buffer!!.byteLength / 2.0) - } + get() = _data.size.toDouble() public constructor(size: Double) { _data = ShortArray(size.toInt()) - _buffer = null - _byteBuffer = null - } - - public constructor(buffer: ArrayBuffer) { - _data = null - _buffer = buffer - _byteBuffer = java.nio.ByteBuffer.wrap(buffer.asByteArray()) } public inline operator fun get(index: Double): Double { return get(index.toInt()) } - fun getInt16FromBuffer(index: Int): Short { - return _byteBuffer!!.getShort(index * 2) - } - public inline operator fun set(index: Double, value: Double) { set(index.toInt(), value) - } public inline operator fun get(index: Int): Double { - return if (_data != null) _data[index].toDouble() else getInt16FromBuffer(index).toDouble() + return _data[index].toDouble() } public inline operator fun set(index: Int, value: Double) { - if (_data != null) { - _data[index] = value.toInt().toShort() - } else { - _byteBuffer!!.putShort((index * 2), value.toInt().toShort()) - } + _data[index] = value.toInt().toShort() } - override fun iterator(): Iterator { - if (_data == null) { - return (0 until length.toInt()).map { getInt16FromBuffer(it) }.iterator() - } + override fun iterator(): ShortIterator { return _data.iterator() } } diff --git a/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Int32Array.kt b/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Int32Array.kt index e607e8846..87db8d675 100644 --- a/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Int32Array.kt +++ b/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Int32Array.kt @@ -47,8 +47,14 @@ internal class Int32Array : Iterable { _data.fill(i) } - override fun iterator(): Iterator { - return (0 until length.toInt()).map { _data[_offset + it] }.iterator() + override fun iterator(): IntIterator { + return ArrayIntIterator(this) + } + + private class ArrayIntIterator(private val array: Int32Array) : IntIterator() { + private var index = 0 + override fun hasNext() = index < array.length + override fun nextInt() = array._data[array._offset + index++] } fun subarray(start: Double, end: Double): Int32Array { diff --git a/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Uint8Array.kt b/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Uint8Array.kt index cb6c589cf..20c63782e 100644 --- a/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Uint8Array.kt +++ b/src.kotlin/alphaTab/android/src/main/java/alphaTab/core/ecmaScript/Uint8Array.kt @@ -47,7 +47,9 @@ public class Uint8Array : Iterable { } internal inline fun set(subarray: Uint8Array, pos: Double) { - subarray.buffer.copyInto(buffer, pos.toInt(), this.byteOffset.toInt(), subarray.buffer.size) + subarray.buffer.copyInto(buffer, (byteOffset + pos).toInt(), + subarray.byteOffset.toInt(), + (subarray.byteOffset + subarray.length).toInt()) } override fun iterator(): Iterator { @@ -56,7 +58,11 @@ public class Uint8Array : Iterable { } internal fun subarray(begin: Double, end: Double): Uint8Array { - return Uint8Array(buffer.copyOfRange((this.byteOffset + begin).toInt(), (this.byteOffset + end).toInt())) + return Uint8Array( + buffer, + this.byteOffset + begin, + end - begin + ) } internal fun reverse() { @@ -65,7 +71,8 @@ public class Uint8Array : Iterable { internal fun slice(startByte: Double, endByte: Double): Uint8Array { return Uint8Array( - this.buffer, this.byteOffset + startByte, + this.buffer, + this.byteOffset + startByte, endByte - startByte) } } diff --git a/src.kotlin/alphaTab/android/src/main/java/alphaTab/platform/android/AndroidAudioWorker.kt b/src.kotlin/alphaTab/android/src/main/java/alphaTab/platform/android/AndroidAudioWorker.kt index b16a82b65..3a5c8abb8 100644 --- a/src.kotlin/alphaTab/android/src/main/java/alphaTab/platform/android/AndroidAudioWorker.kt +++ b/src.kotlin/alphaTab/android/src/main/java/alphaTab/platform/android/AndroidAudioWorker.kt @@ -89,7 +89,7 @@ internal class AndroidAudioWorker( _updateSchedule = _updateTimer.scheduleWithFixedDelay( { this@AndroidAudioWorker.onUpdatePlayedSamples() - }, 0L, 0, TimeUnit.MILLISECONDS + }, 0L, 50L, TimeUnit.MILLISECONDS ) _playingSemaphore.release() // proceed thread diff --git a/src/synth/soundfont/Hydra.ts b/src/synth/soundfont/Hydra.ts index c7afe53cb..ce0d7f459 100644 --- a/src/synth/soundfont/Hydra.ts +++ b/src/synth/soundfont/Hydra.ts @@ -48,10 +48,10 @@ export class Hydra { // 6.1 Sample Data Format in the smpl Sub-chunk // The smpl sub-chunk, if present, contains one or more "samples" of digital audio information in the form // of linearly coded sixteen bit, signed, little endian (least significant byte first) words. - let shorts = new Int16Array(sampleBytes.buffer); - samples = new Float32Array(shorts.length); - for (let i: number = 0; i < shorts.length; i++) { - samples[i] = shorts[i] / 32767; + const dataView = new DataView(sampleBytes.buffer, sampleBytes.byteOffset, sampleBytes.length); + samples = new Float32Array(sampleBytes.length / 2); + for (let i: number = 0; i < samples.length; i++) { + samples[i] = dataView.getInt16(i * 2, true) / 32767; } }