mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 19:51:51 +09:00
TAD: embedded zero tree coding (basically 1D EZBC)
This commit is contained in:
@@ -447,11 +447,11 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
|
|||||||
// decode(y) = sign(y) * |y|^(1/γ) where γ=0.5
|
// decode(y) = sign(y) * |y|^(1/γ) where γ=0.5
|
||||||
val x = left[i]
|
val x = left[i]
|
||||||
val a = kotlin.math.abs(x)
|
val a = kotlin.math.abs(x)
|
||||||
left[i] = signum(x) * a.pow(1.4142f)
|
left[i] = signum(x) * a * a
|
||||||
|
|
||||||
val y = right[i]
|
val y = right[i]
|
||||||
val b = kotlin.math.abs(y)
|
val b = kotlin.math.abs(y)
|
||||||
right[i] = signum(y) * b.pow(1.4142f)
|
right[i] = signum(y) * b * b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,6 +540,218 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Binary Tree EZBC Decoder (1D Variant for TAD)
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
// Bitstream reader for EZBC
|
||||||
|
private class TadBitstreamReader(private val data: ByteArray) {
|
||||||
|
private var bytePos = 0
|
||||||
|
private var bitPos = 0
|
||||||
|
|
||||||
|
fun readBit(): Int {
|
||||||
|
if (bytePos >= data.size) {
|
||||||
|
println("ERROR: Bitstream underflow")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val bit = ((data[bytePos].toInt() and 0xFF) shr bitPos) and 1
|
||||||
|
|
||||||
|
bitPos++
|
||||||
|
if (bitPos == 8) {
|
||||||
|
bitPos = 0
|
||||||
|
bytePos++
|
||||||
|
}
|
||||||
|
|
||||||
|
return bit
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readBits(numBits: Int): Int {
|
||||||
|
var value = 0
|
||||||
|
for (i in 0 until numBits) {
|
||||||
|
value = value or (readBit() shl i)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBytesConsumed(): Int {
|
||||||
|
return bytePos + if (bitPos > 0) 1 else 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block structure for 1D binary tree
|
||||||
|
private data class TadBlock(val start: Int, val length: Int)
|
||||||
|
|
||||||
|
// Queue for block processing
|
||||||
|
private class TadBlockQueue {
|
||||||
|
private val blocks = ArrayList<TadBlock>()
|
||||||
|
|
||||||
|
fun push(block: TadBlock) {
|
||||||
|
blocks.add(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun get(index: Int): TadBlock = blocks[index]
|
||||||
|
|
||||||
|
val size: Int get() = blocks.size
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
blocks.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track coefficient state for refinement
|
||||||
|
private data class TadCoeffState(var significant: Boolean = false, var firstBitplane: Int = 0)
|
||||||
|
|
||||||
|
// Check if all coefficients in block have |coeff| < threshold
|
||||||
|
private fun tadIsZeroBlock(coeffs: ByteArray, block: TadBlock, threshold: Int): Boolean {
|
||||||
|
for (i in block.start until block.start + block.length) {
|
||||||
|
if (kotlin.math.abs(coeffs[i].toInt()) >= threshold) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get MSB position (bitplane number)
|
||||||
|
private fun tadGetMsbBitplane(value: Int): Int {
|
||||||
|
if (value == 0) return 0
|
||||||
|
var bitplane = 0
|
||||||
|
var v = value
|
||||||
|
while (v > 1) {
|
||||||
|
v = v shr 1
|
||||||
|
bitplane++
|
||||||
|
}
|
||||||
|
return bitplane
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively decode a significant block - subdivide until size 1
|
||||||
|
private fun tadDecodeSignificantBlockRecursive(
|
||||||
|
bs: TadBitstreamReader,
|
||||||
|
coeffs: ByteArray,
|
||||||
|
states: Array<TadCoeffState>,
|
||||||
|
bitplane: Int,
|
||||||
|
block: TadBlock,
|
||||||
|
nextInsignificant: TadBlockQueue,
|
||||||
|
nextSignificant: TadBlockQueue
|
||||||
|
) {
|
||||||
|
// If size 1: read sign bit and reconstruct value
|
||||||
|
if (block.length == 1) {
|
||||||
|
val idx = block.start
|
||||||
|
val signBit = bs.readBit()
|
||||||
|
|
||||||
|
// Reconstruct absolute value from bitplane
|
||||||
|
val absVal = 1 shl bitplane
|
||||||
|
|
||||||
|
// Apply sign
|
||||||
|
coeffs[idx] = (if (signBit != 0) -absVal else absVal).toByte()
|
||||||
|
|
||||||
|
states[idx].significant = true
|
||||||
|
states[idx].firstBitplane = bitplane
|
||||||
|
nextSignificant.push(block)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block is > 1: subdivide into left and right halves
|
||||||
|
val mid = block.length / 2.coerceAtLeast(1)
|
||||||
|
|
||||||
|
// Process left child
|
||||||
|
val left = TadBlock(block.start, mid)
|
||||||
|
val leftSig = bs.readBit()
|
||||||
|
if (leftSig != 0) {
|
||||||
|
tadDecodeSignificantBlockRecursive(bs, coeffs, states, bitplane, left, nextInsignificant, nextSignificant)
|
||||||
|
} else {
|
||||||
|
nextInsignificant.push(left)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process right child (if exists)
|
||||||
|
if (block.length > mid) {
|
||||||
|
val right = TadBlock(block.start + mid, block.length - mid)
|
||||||
|
val rightSig = bs.readBit()
|
||||||
|
if (rightSig != 0) {
|
||||||
|
tadDecodeSignificantBlockRecursive(bs, coeffs, states, bitplane, right, nextInsignificant, nextSignificant)
|
||||||
|
} else {
|
||||||
|
nextInsignificant.push(right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binary tree EZBC decoding for a single channel (1D variant)
|
||||||
|
private fun tadDecodeChannelEzbc(input: ByteArray, inputSize: Int, coeffs: ByteArray): Int {
|
||||||
|
val bs = TadBitstreamReader(input)
|
||||||
|
|
||||||
|
// Read header: MSB bitplane and length
|
||||||
|
val msbBitplane = bs.readBits(8)
|
||||||
|
val count = bs.readBits(16)
|
||||||
|
|
||||||
|
// Initialize coefficient array to zero
|
||||||
|
coeffs.fill(0)
|
||||||
|
|
||||||
|
// Track coefficient significance
|
||||||
|
val states = Array(count) { TadCoeffState() }
|
||||||
|
|
||||||
|
// Initialize queues
|
||||||
|
val insignificantQueue = TadBlockQueue()
|
||||||
|
val nextInsignificant = TadBlockQueue()
|
||||||
|
val significantQueue = TadBlockQueue()
|
||||||
|
val nextSignificant = TadBlockQueue()
|
||||||
|
|
||||||
|
// Start with root block as insignificant
|
||||||
|
val root = TadBlock(0, count)
|
||||||
|
insignificantQueue.push(root)
|
||||||
|
|
||||||
|
// Process bitplanes from MSB to LSB
|
||||||
|
for (bitplane in msbBitplane downTo 0) {
|
||||||
|
val threshold = 1 shl bitplane
|
||||||
|
|
||||||
|
// Process insignificant blocks
|
||||||
|
for (i in 0 until insignificantQueue.size) {
|
||||||
|
val block = insignificantQueue.get(i)
|
||||||
|
|
||||||
|
val sig = bs.readBit()
|
||||||
|
if (sig == 0) {
|
||||||
|
// Still insignificant
|
||||||
|
nextInsignificant.push(block)
|
||||||
|
} else {
|
||||||
|
// Became significant: recursively decode
|
||||||
|
tadDecodeSignificantBlockRecursive(
|
||||||
|
bs, coeffs, states, bitplane, block,
|
||||||
|
nextInsignificant, nextSignificant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refinement pass: read next bit for already-significant coefficients
|
||||||
|
for (i in 0 until significantQueue.size) {
|
||||||
|
val block = significantQueue.get(i)
|
||||||
|
val idx = block.start
|
||||||
|
|
||||||
|
val bit = bs.readBit()
|
||||||
|
|
||||||
|
// Add this bit to the coefficient's magnitude
|
||||||
|
if (bit != 0) {
|
||||||
|
val sign = if (coeffs[idx] < 0) -1 else 1
|
||||||
|
val absVal = kotlin.math.abs(coeffs[idx].toInt())
|
||||||
|
coeffs[idx] = (sign * (absVal or (1 shl bitplane))).toByte()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap queues for next bitplane
|
||||||
|
insignificantQueue.clear()
|
||||||
|
for (i in 0 until nextInsignificant.size) {
|
||||||
|
insignificantQueue.push(nextInsignificant.get(i))
|
||||||
|
}
|
||||||
|
nextInsignificant.clear()
|
||||||
|
|
||||||
|
significantQueue.clear()
|
||||||
|
for (i in 0 until nextSignificant.size) {
|
||||||
|
significantQueue.push(nextSignificant.get(i))
|
||||||
|
}
|
||||||
|
nextSignificant.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
return bs.getBytesConsumed()
|
||||||
|
}
|
||||||
|
|
||||||
private fun decodeTad() {
|
private fun decodeTad() {
|
||||||
tadBusy = true
|
tadBusy = true
|
||||||
try {
|
try {
|
||||||
@@ -571,9 +783,23 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode raw int8_t storage (no significance map - encoder uses raw format)
|
// Decode using binary tree EZBC
|
||||||
val quantMid = payload.sliceArray(0 until sampleCount)
|
val quantMid = ByteArray(sampleCount)
|
||||||
val quantSide = payload.sliceArray(sampleCount until sampleCount*2)
|
val quantSide = ByteArray(sampleCount)
|
||||||
|
|
||||||
|
// Decode Mid channel
|
||||||
|
val midBytesConsumed = tadDecodeChannelEzbc(
|
||||||
|
payload,
|
||||||
|
payload.size,
|
||||||
|
quantMid
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decode Side channel (starts after Mid channel data)
|
||||||
|
val sideBytesConsumed = tadDecodeChannelEzbc(
|
||||||
|
payload.sliceArray(midBytesConsumed until payload.size),
|
||||||
|
payload.size - midBytesConsumed,
|
||||||
|
quantSide
|
||||||
|
)
|
||||||
|
|
||||||
// Calculate DWT levels from sample count
|
// Calculate DWT levels from sample count
|
||||||
val dwtLevels = calculateDwtLevels(sampleCount)
|
val dwtLevels = calculateDwtLevels(sampleCount)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include "encoder_tad.h"
|
||||||
|
|
||||||
#define DECODER_VENDOR_STRING "Decoder-TAD 20251026"
|
#define DECODER_VENDOR_STRING "Decoder-TAD 20251026"
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ static const float BASE_QUANTISER_WEIGHTS[2][10] = {
|
|||||||
3.2f // H (L1) 8 khz
|
3.2f // H (L1) 8 khz
|
||||||
}};
|
}};
|
||||||
|
|
||||||
#define TAD_DEFAULT_CHUNK_SIZE 32768
|
#define TAD_DEFAULT_CHUNK_SIZE 31991
|
||||||
#define TAD_MIN_CHUNK_SIZE 1024
|
#define TAD_MIN_CHUNK_SIZE 1024
|
||||||
#define TAD_SAMPLE_RATE 32000
|
#define TAD_SAMPLE_RATE 32000
|
||||||
#define TAD_CHANNELS 2
|
#define TAD_CHANNELS 2
|
||||||
@@ -628,6 +629,238 @@ static void dequantize_dwt_coefficients(int channel, const int8_t *quantized, fl
|
|||||||
free(sideband_starts);
|
free(sideband_starts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Binary Tree EZBC Decoder (1D Variant for TAD)
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// Bitstream reader for EZBC
|
||||||
|
typedef struct {
|
||||||
|
const uint8_t *data;
|
||||||
|
size_t size;
|
||||||
|
size_t byte_pos;
|
||||||
|
uint8_t bit_pos; // 0-7, current bit position in current byte
|
||||||
|
} tad_bitstream_reader_t;
|
||||||
|
|
||||||
|
// Block structure for 1D binary tree (same as encoder)
|
||||||
|
typedef struct {
|
||||||
|
int start;
|
||||||
|
int length;
|
||||||
|
} tad_decode_block_t;
|
||||||
|
|
||||||
|
// Queue for block processing (same as encoder)
|
||||||
|
typedef struct {
|
||||||
|
tad_decode_block_t *blocks;
|
||||||
|
size_t count;
|
||||||
|
size_t capacity;
|
||||||
|
} tad_decode_queue_t;
|
||||||
|
|
||||||
|
// Track coefficient state for refinement
|
||||||
|
typedef struct {
|
||||||
|
bool significant;
|
||||||
|
int first_bitplane;
|
||||||
|
} tad_decode_state_t;
|
||||||
|
|
||||||
|
// Bitstream read operations
|
||||||
|
static void tad_bitstream_reader_init(tad_bitstream_reader_t *bs, const uint8_t *data, size_t size) {
|
||||||
|
bs->data = data;
|
||||||
|
bs->size = size;
|
||||||
|
bs->byte_pos = 0;
|
||||||
|
bs->bit_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tad_bitstream_read_bit(tad_bitstream_reader_t *bs) {
|
||||||
|
if (bs->byte_pos >= bs->size) {
|
||||||
|
fprintf(stderr, "Error: Bitstream underflow\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bit = (bs->data[bs->byte_pos] >> bs->bit_pos) & 1;
|
||||||
|
|
||||||
|
bs->bit_pos++;
|
||||||
|
if (bs->bit_pos == 8) {
|
||||||
|
bs->bit_pos = 0;
|
||||||
|
bs->byte_pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t tad_bitstream_read_bits(tad_bitstream_reader_t *bs, int num_bits) {
|
||||||
|
uint32_t value = 0;
|
||||||
|
for (int i = 0; i < num_bits; i++) {
|
||||||
|
value |= (tad_bitstream_read_bit(bs) << i);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue operations
|
||||||
|
static void tad_decode_queue_init(tad_decode_queue_t *q) {
|
||||||
|
q->capacity = 1024;
|
||||||
|
q->blocks = malloc(q->capacity * sizeof(tad_decode_block_t));
|
||||||
|
q->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tad_decode_queue_push(tad_decode_queue_t *q, tad_decode_block_t block) {
|
||||||
|
if (q->count >= q->capacity) {
|
||||||
|
q->capacity *= 2;
|
||||||
|
q->blocks = realloc(q->blocks, q->capacity * sizeof(tad_decode_block_t));
|
||||||
|
}
|
||||||
|
q->blocks[q->count++] = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tad_decode_queue_free(tad_decode_queue_t *q) {
|
||||||
|
free(q->blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context for recursive EZBC decoding
|
||||||
|
typedef struct {
|
||||||
|
tad_bitstream_reader_t *bs;
|
||||||
|
int8_t *coeffs;
|
||||||
|
tad_decode_state_t *states;
|
||||||
|
int bitplane;
|
||||||
|
tad_decode_queue_t *next_insignificant;
|
||||||
|
tad_decode_queue_t *next_significant;
|
||||||
|
} tad_decode_context_t;
|
||||||
|
|
||||||
|
// Recursively decode a significant block - subdivide until size 1
|
||||||
|
static void tad_decode_significant_block_recursive(tad_decode_context_t *ctx, tad_decode_block_t block) {
|
||||||
|
// If size 1: read sign bit and reconstruct value
|
||||||
|
if (block.length == 1) {
|
||||||
|
int idx = block.start;
|
||||||
|
int sign_bit = tad_bitstream_read_bit(ctx->bs);
|
||||||
|
|
||||||
|
// Reconstruct absolute value from bitplane
|
||||||
|
int abs_val = 1 << ctx->bitplane;
|
||||||
|
|
||||||
|
// Apply sign
|
||||||
|
ctx->coeffs[idx] = sign_bit ? -abs_val : abs_val;
|
||||||
|
|
||||||
|
ctx->states[idx].significant = true;
|
||||||
|
ctx->states[idx].first_bitplane = ctx->bitplane;
|
||||||
|
tad_decode_queue_push(ctx->next_significant, block);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block is > 1: subdivide into left and right halves
|
||||||
|
int mid = block.length / 2;
|
||||||
|
if (mid == 0) mid = 1;
|
||||||
|
|
||||||
|
// Process left child
|
||||||
|
tad_decode_block_t left = {block.start, mid};
|
||||||
|
int left_sig = tad_bitstream_read_bit(ctx->bs);
|
||||||
|
if (left_sig) {
|
||||||
|
tad_decode_significant_block_recursive(ctx, left);
|
||||||
|
} else {
|
||||||
|
tad_decode_queue_push(ctx->next_insignificant, left);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process right child (if exists)
|
||||||
|
if (block.length > mid) {
|
||||||
|
tad_decode_block_t right = {block.start + mid, block.length - mid};
|
||||||
|
int right_sig = tad_bitstream_read_bit(ctx->bs);
|
||||||
|
if (right_sig) {
|
||||||
|
tad_decode_significant_block_recursive(ctx, right);
|
||||||
|
} else {
|
||||||
|
tad_decode_queue_push(ctx->next_insignificant, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binary tree EZBC decoding for a single channel (1D variant)
|
||||||
|
static int tad_decode_channel_ezbc(const uint8_t *input, size_t input_size, int8_t *coeffs, size_t *bytes_consumed) {
|
||||||
|
tad_bitstream_reader_t bs;
|
||||||
|
tad_bitstream_reader_init(&bs, input, input_size);
|
||||||
|
|
||||||
|
// Read header: MSB bitplane and length
|
||||||
|
int msb_bitplane = tad_bitstream_read_bits(&bs, 8);
|
||||||
|
uint32_t count = tad_bitstream_read_bits(&bs, 16);
|
||||||
|
|
||||||
|
// Initialize coefficient array to zero
|
||||||
|
memset(coeffs, 0, count * sizeof(int8_t));
|
||||||
|
|
||||||
|
// Track coefficient significance
|
||||||
|
tad_decode_state_t *states = calloc(count, sizeof(tad_decode_state_t));
|
||||||
|
|
||||||
|
// Initialize queues
|
||||||
|
tad_decode_queue_t insignificant_queue, next_insignificant;
|
||||||
|
tad_decode_queue_t significant_queue, next_significant;
|
||||||
|
|
||||||
|
tad_decode_queue_init(&insignificant_queue);
|
||||||
|
tad_decode_queue_init(&next_insignificant);
|
||||||
|
tad_decode_queue_init(&significant_queue);
|
||||||
|
tad_decode_queue_init(&next_significant);
|
||||||
|
|
||||||
|
// Start with root block as insignificant
|
||||||
|
tad_decode_block_t root = {0, (int)count};
|
||||||
|
tad_decode_queue_push(&insignificant_queue, root);
|
||||||
|
|
||||||
|
// Process bitplanes from MSB to LSB
|
||||||
|
for (int bitplane = msb_bitplane; bitplane >= 0; bitplane--) {
|
||||||
|
// Process insignificant blocks
|
||||||
|
for (size_t i = 0; i < insignificant_queue.count; i++) {
|
||||||
|
tad_decode_block_t block = insignificant_queue.blocks[i];
|
||||||
|
|
||||||
|
int sig = tad_bitstream_read_bit(&bs);
|
||||||
|
if (sig == 0) {
|
||||||
|
// Still insignificant
|
||||||
|
tad_decode_queue_push(&next_insignificant, block);
|
||||||
|
} else {
|
||||||
|
// Became significant: recursively decode
|
||||||
|
tad_decode_context_t ctx = {
|
||||||
|
.bs = &bs,
|
||||||
|
.coeffs = coeffs,
|
||||||
|
.states = states,
|
||||||
|
.bitplane = bitplane,
|
||||||
|
.next_insignificant = &next_insignificant,
|
||||||
|
.next_significant = &next_significant
|
||||||
|
};
|
||||||
|
tad_decode_significant_block_recursive(&ctx, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refinement pass: read next bit for already-significant coefficients
|
||||||
|
for (size_t i = 0; i < significant_queue.count; i++) {
|
||||||
|
tad_decode_block_t block = significant_queue.blocks[i];
|
||||||
|
int idx = block.start;
|
||||||
|
|
||||||
|
int bit = tad_bitstream_read_bit(&bs);
|
||||||
|
|
||||||
|
// Add this bit to the coefficient's magnitude
|
||||||
|
if (bit) {
|
||||||
|
int sign = (coeffs[idx] < 0) ? -1 : 1;
|
||||||
|
int abs_val = abs(coeffs[idx]);
|
||||||
|
abs_val |= (1 << bitplane);
|
||||||
|
coeffs[idx] = sign * abs_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap queues for next bitplane
|
||||||
|
tad_decode_queue_t temp_insig = insignificant_queue;
|
||||||
|
insignificant_queue = next_insignificant;
|
||||||
|
next_insignificant = temp_insig;
|
||||||
|
next_insignificant.count = 0;
|
||||||
|
|
||||||
|
tad_decode_queue_t temp_sig = significant_queue;
|
||||||
|
significant_queue = next_significant;
|
||||||
|
next_significant = temp_sig;
|
||||||
|
next_significant.count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
tad_decode_queue_free(&insignificant_queue);
|
||||||
|
tad_decode_queue_free(&next_insignificant);
|
||||||
|
tad_decode_queue_free(&significant_queue);
|
||||||
|
tad_decode_queue_free(&next_significant);
|
||||||
|
free(states);
|
||||||
|
|
||||||
|
// Calculate bytes consumed
|
||||||
|
*bytes_consumed = bs.byte_pos + (bs.bit_pos > 0 ? 1 : 0);
|
||||||
|
|
||||||
|
return 0; // Success
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Chunk Decoding
|
// Chunk Decoding
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -683,9 +916,31 @@ static int decode_chunk(const uint8_t *input, size_t input_size, uint8_t *pcmu8_
|
|||||||
uint8_t *pcm8_left = malloc(sample_count * sizeof(uint8_t));
|
uint8_t *pcm8_left = malloc(sample_count * sizeof(uint8_t));
|
||||||
uint8_t *pcm8_right = malloc(sample_count * sizeof(uint8_t));
|
uint8_t *pcm8_right = malloc(sample_count * sizeof(uint8_t));
|
||||||
|
|
||||||
// Separate Mid/Side
|
// Decode Mid/Side using binary tree EZBC
|
||||||
memcpy(quant_mid, decompressed, sample_count);
|
size_t mid_bytes_consumed = 0;
|
||||||
memcpy(quant_side, decompressed + sample_count, sample_count);
|
size_t side_bytes_consumed = 0;
|
||||||
|
|
||||||
|
// Decode Mid channel
|
||||||
|
int result = tad_decode_channel_ezbc(decompressed, actual_size, quant_mid, &mid_bytes_consumed);
|
||||||
|
if (result != 0) {
|
||||||
|
fprintf(stderr, "Error: EZBC decoding failed for Mid channel\n");
|
||||||
|
free(decompressed);
|
||||||
|
free(quant_mid); free(quant_side); free(dwt_mid); free(dwt_side);
|
||||||
|
free(pcm32_left); free(pcm32_right); free(pcm8_left); free(pcm8_right);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode Side channel (starts after Mid channel data)
|
||||||
|
result = tad_decode_channel_ezbc(decompressed + mid_bytes_consumed,
|
||||||
|
actual_size - mid_bytes_consumed,
|
||||||
|
quant_side, &side_bytes_consumed);
|
||||||
|
if (result != 0) {
|
||||||
|
fprintf(stderr, "Error: EZBC decoding failed for Side channel\n");
|
||||||
|
free(decompressed);
|
||||||
|
free(quant_mid); free(quant_side); free(dwt_mid); free(dwt_side);
|
||||||
|
free(pcm32_left); free(pcm32_right); free(pcm8_left); free(pcm8_right);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Dequantize with quantiser scaling and spectral interpolation
|
// Dequantize with quantiser scaling and spectral interpolation
|
||||||
// Use quantiser_scale = 1.0f for baseline (must match encoder)
|
// Use quantiser_scale = 1.0f for baseline (must match encoder)
|
||||||
|
|||||||
@@ -854,6 +854,287 @@ void tad32_free_statistics(void) {
|
|||||||
stats_initialized = 0;
|
stats_initialized = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Binary Tree EZBC (1D Variant for TAD)
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// Bitstream writer for EZBC
|
||||||
|
typedef struct {
|
||||||
|
uint8_t *data;
|
||||||
|
size_t capacity;
|
||||||
|
size_t byte_pos;
|
||||||
|
uint8_t bit_pos; // 0-7, current bit position in current byte
|
||||||
|
} tad_bitstream_t;
|
||||||
|
|
||||||
|
// Block structure for 1D binary tree
|
||||||
|
typedef struct {
|
||||||
|
int start; // Start index in 1D array
|
||||||
|
int length; // Block length
|
||||||
|
} tad_block_t;
|
||||||
|
|
||||||
|
// Queue for block processing
|
||||||
|
typedef struct {
|
||||||
|
tad_block_t *blocks;
|
||||||
|
size_t count;
|
||||||
|
size_t capacity;
|
||||||
|
} tad_block_queue_t;
|
||||||
|
|
||||||
|
// Track coefficient state for refinement
|
||||||
|
typedef struct {
|
||||||
|
bool significant; // Has been marked significant
|
||||||
|
int first_bitplane; // Bitplane where it became significant
|
||||||
|
} tad_coeff_state_t;
|
||||||
|
|
||||||
|
// Bitstream operations
|
||||||
|
static void tad_bitstream_init(tad_bitstream_t *bs, size_t initial_capacity) {
|
||||||
|
bs->capacity = initial_capacity;
|
||||||
|
bs->data = calloc(1, initial_capacity);
|
||||||
|
bs->byte_pos = 0;
|
||||||
|
bs->bit_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tad_bitstream_write_bit(tad_bitstream_t *bs, int bit) {
|
||||||
|
// Grow if needed
|
||||||
|
if (bs->byte_pos >= bs->capacity) {
|
||||||
|
bs->capacity *= 2;
|
||||||
|
bs->data = realloc(bs->data, bs->capacity);
|
||||||
|
// Clear new memory
|
||||||
|
memset(bs->data + bs->byte_pos, 0, bs->capacity - bs->byte_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bit) {
|
||||||
|
bs->data[bs->byte_pos] |= (1 << bs->bit_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
bs->bit_pos++;
|
||||||
|
if (bs->bit_pos == 8) {
|
||||||
|
bs->bit_pos = 0;
|
||||||
|
bs->byte_pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tad_bitstream_write_bits(tad_bitstream_t *bs, uint32_t value, int num_bits) {
|
||||||
|
for (int i = 0; i < num_bits; i++) {
|
||||||
|
tad_bitstream_write_bit(bs, (value >> i) & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t tad_bitstream_size(tad_bitstream_t *bs) {
|
||||||
|
return bs->byte_pos + (bs->bit_pos > 0 ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tad_bitstream_free(tad_bitstream_t *bs) {
|
||||||
|
free(bs->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block queue operations
|
||||||
|
static void tad_queue_init(tad_block_queue_t *q) {
|
||||||
|
q->capacity = 1024;
|
||||||
|
q->blocks = malloc(q->capacity * sizeof(tad_block_t));
|
||||||
|
q->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tad_queue_push(tad_block_queue_t *q, tad_block_t block) {
|
||||||
|
if (q->count >= q->capacity) {
|
||||||
|
q->capacity *= 2;
|
||||||
|
q->blocks = realloc(q->blocks, q->capacity * sizeof(tad_block_t));
|
||||||
|
}
|
||||||
|
q->blocks[q->count++] = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tad_queue_free(tad_block_queue_t *q) {
|
||||||
|
free(q->blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all coefficients in block have |coeff| < threshold
|
||||||
|
static bool tad_is_zero_block(int8_t *coeffs, const tad_block_t *block, int threshold) {
|
||||||
|
for (int i = block->start; i < block->start + block->length; i++) {
|
||||||
|
if (abs(coeffs[i]) >= threshold) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find maximum absolute coefficient value
|
||||||
|
static int tad_find_max_abs(int8_t *coeffs, size_t count) {
|
||||||
|
int max_abs = 0;
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
int abs_val = abs(coeffs[i]);
|
||||||
|
if (abs_val > max_abs) {
|
||||||
|
max_abs = abs_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max_abs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get MSB position (bitplane number)
|
||||||
|
static int tad_get_msb_bitplane(int value) {
|
||||||
|
if (value == 0) return 0;
|
||||||
|
int bitplane = 0;
|
||||||
|
while (value > 1) {
|
||||||
|
value >>= 1;
|
||||||
|
bitplane++;
|
||||||
|
}
|
||||||
|
return bitplane;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context for recursive EZBC processing
|
||||||
|
typedef struct {
|
||||||
|
tad_bitstream_t *bs;
|
||||||
|
int8_t *coeffs;
|
||||||
|
tad_coeff_state_t *states;
|
||||||
|
int length;
|
||||||
|
int bitplane;
|
||||||
|
int threshold;
|
||||||
|
tad_block_queue_t *next_insignificant;
|
||||||
|
tad_block_queue_t *next_significant;
|
||||||
|
int *sign_count;
|
||||||
|
} tad_ezbc_context_t;
|
||||||
|
|
||||||
|
// Recursively process a significant block - subdivide until size 1
|
||||||
|
static void tad_process_significant_block_recursive(tad_ezbc_context_t *ctx, tad_block_t block) {
|
||||||
|
// If size 1: emit sign bit and add to significant queue
|
||||||
|
if (block.length == 1) {
|
||||||
|
int idx = block.start;
|
||||||
|
tad_bitstream_write_bit(ctx->bs, ctx->coeffs[idx] < 0 ? 1 : 0);
|
||||||
|
(*ctx->sign_count)++;
|
||||||
|
ctx->states[idx].significant = true;
|
||||||
|
ctx->states[idx].first_bitplane = ctx->bitplane;
|
||||||
|
tad_queue_push(ctx->next_significant, block);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block is > 1: subdivide into left and right halves
|
||||||
|
int mid = block.length / 2;
|
||||||
|
if (mid == 0) mid = 1;
|
||||||
|
|
||||||
|
// Process left child
|
||||||
|
tad_block_t left = {block.start, mid};
|
||||||
|
if (!tad_is_zero_block(ctx->coeffs, &left, ctx->threshold)) {
|
||||||
|
tad_bitstream_write_bit(ctx->bs, 1); // Significant
|
||||||
|
tad_process_significant_block_recursive(ctx, left);
|
||||||
|
} else {
|
||||||
|
tad_bitstream_write_bit(ctx->bs, 0); // Insignificant
|
||||||
|
tad_queue_push(ctx->next_insignificant, left);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process right child (if exists)
|
||||||
|
if (block.length > mid) {
|
||||||
|
tad_block_t right = {block.start + mid, block.length - mid};
|
||||||
|
if (!tad_is_zero_block(ctx->coeffs, &right, ctx->threshold)) {
|
||||||
|
tad_bitstream_write_bit(ctx->bs, 1);
|
||||||
|
tad_process_significant_block_recursive(ctx, right);
|
||||||
|
} else {
|
||||||
|
tad_bitstream_write_bit(ctx->bs, 0);
|
||||||
|
tad_queue_push(ctx->next_insignificant, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binary tree EZBC encoding for a single channel (1D variant)
|
||||||
|
static size_t tad_encode_channel_ezbc(int8_t *coeffs, size_t count, uint8_t **output) {
|
||||||
|
tad_bitstream_t bs;
|
||||||
|
tad_bitstream_init(&bs, count / 4); // Initial guess
|
||||||
|
|
||||||
|
// Track coefficient significance
|
||||||
|
tad_coeff_state_t *states = calloc(count, sizeof(tad_coeff_state_t));
|
||||||
|
|
||||||
|
// Find maximum value to determine MSB bitplane
|
||||||
|
int max_abs = tad_find_max_abs(coeffs, count);
|
||||||
|
int msb_bitplane = tad_get_msb_bitplane(max_abs);
|
||||||
|
|
||||||
|
// Write header: MSB bitplane and length
|
||||||
|
tad_bitstream_write_bits(&bs, msb_bitplane, 8);
|
||||||
|
tad_bitstream_write_bits(&bs, (uint32_t)count, 16);
|
||||||
|
|
||||||
|
// Initialize queues
|
||||||
|
tad_block_queue_t insignificant_queue, next_insignificant;
|
||||||
|
tad_block_queue_t significant_queue, next_significant;
|
||||||
|
|
||||||
|
tad_queue_init(&insignificant_queue);
|
||||||
|
tad_queue_init(&next_insignificant);
|
||||||
|
tad_queue_init(&significant_queue);
|
||||||
|
tad_queue_init(&next_significant);
|
||||||
|
|
||||||
|
// Start with root block as insignificant
|
||||||
|
tad_block_t root = {0, (int)count};
|
||||||
|
tad_queue_push(&insignificant_queue, root);
|
||||||
|
|
||||||
|
// Process bitplanes from MSB to LSB
|
||||||
|
for (int bitplane = msb_bitplane; bitplane >= 0; bitplane--) {
|
||||||
|
int threshold = 1 << bitplane;
|
||||||
|
|
||||||
|
// Process insignificant blocks - check if they become significant
|
||||||
|
for (size_t i = 0; i < insignificant_queue.count; i++) {
|
||||||
|
tad_block_t block = insignificant_queue.blocks[i];
|
||||||
|
|
||||||
|
if (tad_is_zero_block(coeffs, &block, threshold)) {
|
||||||
|
// Still insignificant: emit 0
|
||||||
|
tad_bitstream_write_bit(&bs, 0);
|
||||||
|
// Keep in insignificant queue for next bitplane
|
||||||
|
tad_queue_push(&next_insignificant, block);
|
||||||
|
} else {
|
||||||
|
// Became significant: emit 1
|
||||||
|
tad_bitstream_write_bit(&bs, 1);
|
||||||
|
|
||||||
|
// Use recursive subdivision
|
||||||
|
int sign_count = 0;
|
||||||
|
tad_ezbc_context_t ctx = {
|
||||||
|
.bs = &bs,
|
||||||
|
.coeffs = coeffs,
|
||||||
|
.states = states,
|
||||||
|
.length = (int)count,
|
||||||
|
.bitplane = bitplane,
|
||||||
|
.threshold = threshold,
|
||||||
|
.next_insignificant = &next_insignificant,
|
||||||
|
.next_significant = &next_significant,
|
||||||
|
.sign_count = &sign_count
|
||||||
|
};
|
||||||
|
tad_process_significant_block_recursive(&ctx, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refinement pass: emit next bit for already-significant coefficients
|
||||||
|
for (size_t i = 0; i < significant_queue.count; i++) {
|
||||||
|
tad_block_t block = significant_queue.blocks[i];
|
||||||
|
int idx = block.start;
|
||||||
|
|
||||||
|
// Emit refinement bit (bit at position 'bitplane')
|
||||||
|
int bit = (abs(coeffs[idx]) >> bitplane) & 1;
|
||||||
|
tad_bitstream_write_bit(&bs, bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap queues for next bitplane
|
||||||
|
tad_block_queue_t temp_insig = insignificant_queue;
|
||||||
|
insignificant_queue = next_insignificant;
|
||||||
|
next_insignificant = temp_insig;
|
||||||
|
next_insignificant.count = 0; // Clear for reuse
|
||||||
|
|
||||||
|
tad_block_queue_t temp_sig = significant_queue;
|
||||||
|
significant_queue = next_significant;
|
||||||
|
next_significant = temp_sig;
|
||||||
|
next_significant.count = 0; // Clear for reuse
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup queues
|
||||||
|
tad_queue_free(&insignificant_queue);
|
||||||
|
tad_queue_free(&next_insignificant);
|
||||||
|
tad_queue_free(&significant_queue);
|
||||||
|
tad_queue_free(&next_significant);
|
||||||
|
free(states);
|
||||||
|
|
||||||
|
// Copy bitstream to output
|
||||||
|
size_t output_size = tad_bitstream_size(&bs);
|
||||||
|
*output = malloc(output_size);
|
||||||
|
memcpy(*output, bs.data, output_size);
|
||||||
|
tad_bitstream_free(&bs);
|
||||||
|
|
||||||
|
return output_size;
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Public API: Chunk Encoding
|
// Public API: Chunk Encoding
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -931,17 +1212,21 @@ size_t tad32_encode_chunk(const float *pcm32_stereo, size_t num_samples,
|
|||||||
accumulate_quantized(quant_side, dwt_levels, num_samples, side_quant_accumulators);
|
accumulate_quantized(quant_side, dwt_levels, num_samples, side_quant_accumulators);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5: Encode with twobit-map significance map or raw int8_t storage
|
// Step 5: Encode with binary tree EZBC (1D variant)
|
||||||
uint8_t *temp_buffer = malloc(num_samples * 4); // Generous buffer
|
uint8_t *mid_ezbc = NULL;
|
||||||
size_t mid_size, side_size;
|
uint8_t *side_ezbc = NULL;
|
||||||
|
|
||||||
// Raw int8_t storage
|
size_t mid_size = tad_encode_channel_ezbc(quant_mid, num_samples, &mid_ezbc);
|
||||||
memcpy(temp_buffer, quant_mid, num_samples);
|
size_t side_size = tad_encode_channel_ezbc(quant_side, num_samples, &side_ezbc);
|
||||||
mid_size = num_samples;
|
|
||||||
memcpy(temp_buffer + mid_size, quant_side, num_samples);
|
|
||||||
side_size = num_samples;
|
|
||||||
|
|
||||||
|
// Concatenate EZBC outputs
|
||||||
size_t uncompressed_size = mid_size + side_size;
|
size_t uncompressed_size = mid_size + side_size;
|
||||||
|
uint8_t *temp_buffer = malloc(uncompressed_size);
|
||||||
|
memcpy(temp_buffer, mid_ezbc, mid_size);
|
||||||
|
memcpy(temp_buffer + mid_size, side_ezbc, side_size);
|
||||||
|
|
||||||
|
free(mid_ezbc);
|
||||||
|
free(side_ezbc);
|
||||||
|
|
||||||
// Step 6: Optional Zstd compression
|
// Step 6: Optional Zstd compression
|
||||||
uint8_t *write_ptr = output;
|
uint8_t *write_ptr = output;
|
||||||
|
|||||||
@@ -13,13 +13,11 @@
|
|||||||
#define TAD32_MIN_CHUNK_SIZE 1024 // Minimum: 1024 samples
|
#define TAD32_MIN_CHUNK_SIZE 1024 // Minimum: 1024 samples
|
||||||
#define TAD32_SAMPLE_RATE 32000
|
#define TAD32_SAMPLE_RATE 32000
|
||||||
#define TAD32_CHANNELS 2 // Stereo
|
#define TAD32_CHANNELS 2 // Stereo
|
||||||
#define TAD32_SIGMAP_2BIT 1 // 2-bit: 00=0, 01=+1, 10=-1, 11=other
|
|
||||||
#define TAD32_QUALITY_MIN 0
|
#define TAD32_QUALITY_MIN 0
|
||||||
#define TAD32_QUALITY_MAX 6
|
#define TAD32_QUALITY_MAX 6
|
||||||
#define TAD32_QUALITY_DEFAULT 3
|
#define TAD32_QUALITY_DEFAULT 3
|
||||||
#define TAD32_ZSTD_LEVEL 15
|
#define TAD32_ZSTD_LEVEL 15
|
||||||
|
|
||||||
|
|
||||||
static inline int tad32_quality_to_max_index(int quality) {
|
static inline int tad32_quality_to_max_index(int quality) {
|
||||||
static const int quality_map[6] = {21, 31, 44, 63, 89, 127};
|
static const int quality_map[6] = {21, 31, 44, 63, 89, 127};
|
||||||
if (quality < 0) quality = 0;
|
if (quality < 0) quality = 0;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#define ENCODER_VENDOR_STRING "Encoder-TAD32 (PCM32f version) 20251107"
|
#define ENCODER_VENDOR_STRING "Encoder-TAD32 (PCM32f version) 20251107"
|
||||||
|
|
||||||
// TAD32 format constants
|
// TAD32 format constants
|
||||||
#define TAD32_DEFAULT_CHUNK_SIZE 32768 // Default: power of 2 for optimal performance (2^15)
|
#define TAD32_DEFAULT_CHUNK_SIZE 31991 // Using a prime number to force the worst condition
|
||||||
|
|
||||||
// Temporary file for FFmpeg PCM extraction
|
// Temporary file for FFmpeg PCM extraction
|
||||||
char TEMP_PCM_FILE[42];
|
char TEMP_PCM_FILE[42];
|
||||||
|
|||||||
Reference in New Issue
Block a user