diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt index aa56103..76ce2ec 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt @@ -447,11 +447,11 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) { // decode(y) = sign(y) * |y|^(1/γ) where γ=0.5 val x = left[i] 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 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() + + 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, + 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() { tadBusy = true try { @@ -571,9 +783,23 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) { return } - // 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) + // Decode using binary tree EZBC + val quantMid = ByteArray(sampleCount) + 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 val dwtLevels = calculateDwtLevels(sampleCount) diff --git a/video_encoder/decoder_tad.c b/video_encoder/decoder_tad.c index 3a00021..11b2982 100644 --- a/video_encoder/decoder_tad.c +++ b/video_encoder/decoder_tad.c @@ -8,6 +8,7 @@ #include #include #include +#include "encoder_tad.h" #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 }}; -#define TAD_DEFAULT_CHUNK_SIZE 32768 +#define TAD_DEFAULT_CHUNK_SIZE 31991 #define TAD_MIN_CHUNK_SIZE 1024 #define TAD_SAMPLE_RATE 32000 #define TAD_CHANNELS 2 @@ -628,6 +629,238 @@ static void dequantize_dwt_coefficients(int channel, const int8_t *quantized, fl free(sideband_starts); } +//============================================================================= +// Binary Tree EZBC Decoder (1D Variant for TAD) +//============================================================================= + +#include + +// 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 //============================================================================= @@ -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_right = malloc(sample_count * sizeof(uint8_t)); - // Separate Mid/Side - memcpy(quant_mid, decompressed, sample_count); - memcpy(quant_side, decompressed + sample_count, sample_count); + // Decode Mid/Side using binary tree EZBC + size_t mid_bytes_consumed = 0; + 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 // Use quantiser_scale = 1.0f for baseline (must match encoder) diff --git a/video_encoder/encoder_tad.c b/video_encoder/encoder_tad.c index 878b10e..4dc0133 100644 --- a/video_encoder/encoder_tad.c +++ b/video_encoder/encoder_tad.c @@ -854,6 +854,287 @@ void tad32_free_statistics(void) { stats_initialized = 0; } +//============================================================================= +// Binary Tree EZBC (1D Variant for TAD) +//============================================================================= + +#include + +// 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 //============================================================================= @@ -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); } - // Step 5: Encode with twobit-map significance map or raw int8_t storage - uint8_t *temp_buffer = malloc(num_samples * 4); // Generous buffer - size_t mid_size, side_size; + // Step 5: Encode with binary tree EZBC (1D variant) + uint8_t *mid_ezbc = NULL; + uint8_t *side_ezbc = NULL; - // Raw int8_t storage - memcpy(temp_buffer, quant_mid, num_samples); - mid_size = num_samples; - memcpy(temp_buffer + mid_size, quant_side, num_samples); - side_size = num_samples; + size_t mid_size = tad_encode_channel_ezbc(quant_mid, num_samples, &mid_ezbc); + size_t side_size = tad_encode_channel_ezbc(quant_side, num_samples, &side_ezbc); + // Concatenate EZBC outputs 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 uint8_t *write_ptr = output; diff --git a/video_encoder/encoder_tad.h b/video_encoder/encoder_tad.h index d42c27d..74f2062 100644 --- a/video_encoder/encoder_tad.h +++ b/video_encoder/encoder_tad.h @@ -13,13 +13,11 @@ #define TAD32_MIN_CHUNK_SIZE 1024 // Minimum: 1024 samples #define TAD32_SAMPLE_RATE 32000 #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_MAX 6 #define TAD32_QUALITY_DEFAULT 3 #define TAD32_ZSTD_LEVEL 15 - static inline int tad32_quality_to_max_index(int quality) { static const int quality_map[6] = {21, 31, 44, 63, 89, 127}; if (quality < 0) quality = 0; diff --git a/video_encoder/encoder_tad_standalone.c b/video_encoder/encoder_tad_standalone.c index 179a9cb..1a6abad 100644 --- a/video_encoder/encoder_tad_standalone.c +++ b/video_encoder/encoder_tad_standalone.c @@ -15,7 +15,7 @@ #define ENCODER_VENDOR_STRING "Encoder-TAD32 (PCM32f version) 20251107" // 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 char TEMP_PCM_FILE[42];