TAD: working kotlin decoder

This commit is contained in:
minjaesong
2025-10-30 17:08:42 +09:00
parent 480d2d8538
commit 991d035bcc
9 changed files with 405 additions and 134 deletions

View File

@@ -94,13 +94,6 @@ class AudioJSR223Delegate(private val vm: VM) {
}
}
// TAD (Terrarum Advanced Audio) decoder functions
fun tadSetQuality(quality: Int) {
getFirstSnd()?.mmio_write(43L, quality.toByte())
}
fun tadGetQuality() = getFirstSnd()?.mmio_read(43L)?.toInt()
fun tadDecode() {
getFirstSnd()?.mmio_write(42L, 1)
}

View File

@@ -372,9 +372,9 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
// Lambda-based decompanding decoder (inverse of Laplacian CDF-based encoder)
// Converts quantized index back to normalized float in [-1, 1]
private fun lambdaDecompanding(quantVal: Short, maxIndex: Int): Float {
private fun lambdaDecompanding(quantVal: Byte, maxIndex: Int): Float {
// Handle zero
if (quantVal == 0.toShort()) {
if (quantVal == 0.toByte()) {
return 0.0f
}
@@ -477,17 +477,19 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
var offset = 0L
val sampleCount = (
(tadInputBin[offset++].toInt() and 0xFF) or
((tadInputBin[offset++].toInt() and 0xFF) shl 8)
(tadInputBin[offset++].toUint()) or
((tadInputBin[offset++].toUint()) shl 8)
)
val maxIndex = tadInputBin[offset++].toInt() and 0xFF
val maxIndex = tadInputBin[offset++].toUint()
val payloadSize = (
(tadInputBin[offset++].toInt() and 0xFF) or
((tadInputBin[offset++].toInt() and 0xFF) shl 8) or
((tadInputBin[offset++].toInt() and 0xFF) shl 16) or
((tadInputBin[offset++].toInt() and 0xFF) shl 24)
(tadInputBin[offset++].toUint()) or
((tadInputBin[offset++].toUint()) shl 8) or
((tadInputBin[offset++].toUint()) shl 16) or
((tadInputBin[offset++].toUint()) shl 24)
)
// println("Q$maxIndex, SampleCount: $sampleCount, payloadSize: $payloadSize")
// Decompress payload
val compressed = ByteArray(payloadSize)
UnsafeHelper.memcpyRaw(null, tadInputBin.ptr + offset, compressed, UnsafeHelper.getArrayOffset(compressed), payloadSize.toLong())
@@ -501,15 +503,9 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
return
}
// Decode significance maps
val quantMid = ShortArray(sampleCount)
val quantSide = ShortArray(sampleCount)
var payloadOffset = 0
val midBytes = decodeSigmap2bit(payload, payloadOffset, quantMid, sampleCount)
payloadOffset += midBytes
val sideBytes = decodeSigmap2bit(payload, payloadOffset, quantSide, sampleCount)
// Decode raw int8_t storage (no significance map - encoder uses raw format)
val quantMid = payload.sliceArray(0 until sampleCount)
val quantSide = payload.sliceArray(sampleCount until sampleCount*2)
// Calculate DWT levels from sample count
val dwtLevels = calculateDwtLevels(sampleCount)
@@ -542,42 +538,6 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
}
}
private fun decodeSigmap2bit(input: ByteArray, offset: Int, values: ShortArray, count: Int): Int {
val mapBytes = (count * 2 + 7) / 8
var readPtr = offset + mapBytes
var otherIdx = 0
for (i in 0 until count) {
val bitPos = i * 2
val byteIdx = offset + bitPos / 8
val bitOffset = bitPos % 8
var code = ((input[byteIdx].toInt() and 0xFF) shr bitOffset) and 0x03
// Handle bit spillover
if (bitOffset == 7) {
code = ((input[byteIdx].toInt() and 0xFF) shr 7) or
(((input[byteIdx + 1].toInt() and 0xFF) and 0x01) shl 1)
}
values[i] = when (code) {
0 -> 0
1 -> 1
2 -> (-1).toShort()
3 -> {
val v = ((input[readPtr].toInt() and 0xFF) or
((input[readPtr + 1].toInt() and 0xFF) shl 8)).toShort()
readPtr += 2
otherIdx++
v
}
else -> 0
}
}
return mapBytes + otherIdx * 2
}
private fun calculateDwtLevels(chunkSize: Int): Int {
// Hard-coded to 9 levels to match C decoder
return 9
@@ -628,7 +588,7 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
}
}
private fun dequantizeDwtCoefficients(quantized: ShortArray, coeffs: FloatArray, count: Int,
private fun dequantizeDwtCoefficients(quantized: ByteArray, coeffs: FloatArray, count: Int,
maxIndex: Int, dwtLevels: Int) {
// Calculate sideband boundaries dynamically
val firstBandSize = count shr dwtLevels