mirror of
https://github.com/IllusionMan1212/flac-odin.git
synced 2026-10-24 02:12:29 +00:00
A few speed optimizations, still not great
This commit is contained in:
@@ -9,6 +9,7 @@ import "core:slice"
|
|||||||
import "core:io"
|
import "core:io"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import "core:prof/spall"
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
FLAC_MAGIC :: 'f' << 24 | 'L' << 16 | 'a' << 8 | 'C'
|
FLAC_MAGIC :: 'f' << 24 | 'L' << 16 | 'a' << 8 | 'C'
|
||||||
@@ -252,6 +253,15 @@ StreamInfoBlock :: struct #packed {
|
|||||||
md5: [16]byte,
|
md5: [16]byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#assert(size_of(PictureMetadata) == 20)
|
||||||
|
PictureMetadata :: struct {
|
||||||
|
width: u32be,
|
||||||
|
height: u32be,
|
||||||
|
depth: u32be,
|
||||||
|
num_colors: u32be,
|
||||||
|
data_len: u32be,
|
||||||
|
}
|
||||||
|
|
||||||
#assert(size_of(CueSheet) == 396)
|
#assert(size_of(CueSheet) == 396)
|
||||||
CueSheet :: struct #packed {
|
CueSheet :: struct #packed {
|
||||||
media_catalog_num: [128]byte,
|
media_catalog_num: [128]byte,
|
||||||
@@ -285,13 +295,13 @@ CueSheetTrackIndex :: struct #packed {
|
|||||||
reserved: [3]byte,
|
reserved: [3]byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32, err: Error) {
|
decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32, err: Error) #no_bounds_check {
|
||||||
subframe_type_str := ""
|
subframe_type_str := ""
|
||||||
// TODO: temp allocator?? so we copy the slice of data into the _actual_ sample buffer
|
// TODO: temp allocator?? so we copy the slice of data into the _actual_ sample buffer
|
||||||
// Maybe even a static arena with a size of 32MB by default (and configurable using #config) or something
|
// Maybe even a static arena with a size of 32MB by default (and configurable using #config) or something
|
||||||
// that we then use to allocate from (better perf is the reason because allocating on the heap for every subframe
|
// that we then use to allocate from (better perf is the reason because allocating on the heap for every subframe
|
||||||
// is probably noticibly slower)
|
// is probably noticibly slower)
|
||||||
subframe_samples := make([dynamic]i32, 0, block_size)
|
subframe_samples := make([]i32, block_size)
|
||||||
|
|
||||||
//fmt.println("SUBFRAME START AT OFFSET:", r.i)
|
//fmt.println("SUBFRAME START AT OFFSET:", r.i)
|
||||||
//fmt.println("SUBFRAME offset bits", r.bits_read_in_byte)
|
//fmt.println("SUBFRAME offset bits", r.bits_read_in_byte)
|
||||||
@@ -322,10 +332,11 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
bits_to_read := int(bps) - wasted_bits
|
bits_to_read := int(bps) - wasted_bits
|
||||||
sample := i32(read_bits(r, bits_to_read) or_return)
|
sample := i32(read_bits(r, bits_to_read) or_return)
|
||||||
if sample > 0 && (sample >> (uint(bits_to_read) - 1)) & 1 == 1 {
|
if sample > 0 && (sample >> (uint(bits_to_read) - 1)) & 1 == 1 {
|
||||||
sample = -(((~sample) & (i32(math.pow2_f32(bits_to_read)) - 1)) + 1)
|
sample = -(((~sample) & (i32(pow2(bits_to_read)) - 1)) + 1)
|
||||||
}
|
}
|
||||||
for s in 0..<block_size {
|
for s in 0..<block_size {
|
||||||
append(&subframe_samples, sample)
|
subframe_samples[s] = sample
|
||||||
|
//append(&subframe_samples, sample)
|
||||||
}
|
}
|
||||||
} else if subframe_type == 1 { // VERBATIM
|
} else if subframe_type == 1 { // VERBATIM
|
||||||
//fmt.println("SUBFRAME: VERBATIM")
|
//fmt.println("SUBFRAME: VERBATIM")
|
||||||
@@ -352,8 +363,8 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
//unencoded_subblock_arr := transmute([2]byte)unencoded_subblock
|
//unencoded_subblock_arr := transmute([2]byte)unencoded_subblock
|
||||||
//fmt.printfln("arr: %X", unencoded_subblock_arr)
|
//fmt.printfln("arr: %X", unencoded_subblock_arr)
|
||||||
//fmt.printfln("arr as u16: %X", transmute(u16)unencoded_subblock_arr)
|
//fmt.printfln("arr as u16: %X", transmute(u16)unencoded_subblock_arr)
|
||||||
append(&subframe_samples, unencoded_subblock)
|
//append(&subframe_samples, unencoded_subblock)
|
||||||
//append(&decoded_samples, ..unencoded_subblock_arr[:])
|
subframe_samples[sample] = unencoded_subblock
|
||||||
}
|
}
|
||||||
} else if (subframe_type >> 5) & 1 == 1 { // LPC
|
} else if (subframe_type >> 5) & 1 == 1 { // LPC
|
||||||
//fmt.println("SUBFRAME: LPC")
|
//fmt.println("SUBFRAME: LPC")
|
||||||
@@ -368,13 +379,14 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
unencoded_warmup_sample := i32(read_bits(r, bits_to_read) or_return)
|
unencoded_warmup_sample := i32(read_bits(r, bits_to_read) or_return)
|
||||||
// fmt.println("warmup sample:", unencoded_warmup_sample)
|
// fmt.println("warmup sample:", unencoded_warmup_sample)
|
||||||
if unencoded_warmup_sample > 0 && (unencoded_warmup_sample >> (uint(bits_to_read) - 1)) & 1 == 1 {
|
if unencoded_warmup_sample > 0 && (unencoded_warmup_sample >> (uint(bits_to_read) - 1)) & 1 == 1 {
|
||||||
unencoded_warmup_sample = -(((~unencoded_warmup_sample) & (i32(math.pow2_f32(bits_to_read)) - 1)) + 1)
|
unencoded_warmup_sample = -(((~unencoded_warmup_sample) & (i32(pow2(bits_to_read)) - 1)) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
//fmt.printfln("unencoded warmup sample: 0b%b", unencoded_warmup_sample)
|
//fmt.printfln("unencoded warmup sample: 0b%b", unencoded_warmup_sample)
|
||||||
//fmt.println("unencoded warmup sample:", unencoded_warmup_sample)
|
//fmt.println("unencoded warmup sample:", unencoded_warmup_sample)
|
||||||
//fmt.printfln("unencoded warmup sample: 0x%X", unencoded_warmup_sample)
|
//fmt.printfln("unencoded warmup sample: 0x%X", unencoded_warmup_sample)
|
||||||
append(&subframe_samples, unencoded_warmup_sample)
|
//append(&subframe_samples, unencoded_warmup_sample)
|
||||||
|
subframe_samples[s] = unencoded_warmup_sample
|
||||||
}
|
}
|
||||||
|
|
||||||
coeff_precision_minus_one := u8(read_bits(r, 4) or_return)
|
coeff_precision_minus_one := u8(read_bits(r, 4) or_return)
|
||||||
@@ -386,7 +398,7 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
coeff_bits_to_shift := i8(read_bits(r, 5) or_return)
|
coeff_bits_to_shift := i8(read_bits(r, 5) or_return)
|
||||||
// NOTE: This is signed 2's complement so we check the MSB
|
// NOTE: This is signed 2's complement so we check the MSB
|
||||||
// NOTE: This is apparently supposed to never be a negative number according to the spec.
|
// NOTE: This is apparently supposed to never be a negative number according to the spec.
|
||||||
// TODO: For now we just error if the shift value is negative. I have to find test cases to be sure.
|
// TODO: For now we just error if the shift value is negative. I have to find test cases to be sure.
|
||||||
if (coeff_bits_to_shift >> (5 - 1)) & 1 == 1 {
|
if (coeff_bits_to_shift >> (5 - 1)) & 1 == 1 {
|
||||||
//fmt.println("BITS TO SHIFT IS NEGATIVE")
|
//fmt.println("BITS TO SHIFT IS NEGATIVE")
|
||||||
//coeff_bits_to_shift = -(((~coeff_bits_to_shift) & i8(math.pow2_f32(5) - 1)) + 1)
|
//coeff_bits_to_shift = -(((~coeff_bits_to_shift) & i8(math.pow2_f32(5) - 1)) + 1)
|
||||||
@@ -402,7 +414,7 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
unencoded_coefficient := i32(read_bits(r, int(coeff_precision)) or_return)
|
unencoded_coefficient := i32(read_bits(r, int(coeff_precision)) or_return)
|
||||||
// Ditto
|
// Ditto
|
||||||
if unencoded_coefficient > 0 && (unencoded_coefficient >> (coeff_precision - 1)) & 1 == 1 {
|
if unencoded_coefficient > 0 && (unencoded_coefficient >> (coeff_precision - 1)) & 1 == 1 {
|
||||||
unencoded_coefficient = -(((~unencoded_coefficient) & (i32(math.pow2_f32(coeff_precision)) - 1)) + 1)
|
unencoded_coefficient = -(((~unencoded_coefficient) & (i32(pow2(coeff_precision)) - 1)) + 1)
|
||||||
}
|
}
|
||||||
coefficients[i] = unencoded_coefficient
|
coefficients[i] = unencoded_coefficient
|
||||||
//fmt.println("unencoded_coefficient", unencoded_coefficient)
|
//fmt.println("unencoded_coefficient", unencoded_coefficient)
|
||||||
@@ -416,7 +428,7 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
|
|
||||||
partition_order := read_bits(r, 4) or_return
|
partition_order := read_bits(r, 4) or_return
|
||||||
//fmt.println("parition order", partition_order)
|
//fmt.println("parition order", partition_order)
|
||||||
partitions := int(math.pow2_f32(partition_order))
|
partitions := int(pow2(partition_order))
|
||||||
//fmt.println("partitions:", partitions)
|
//fmt.println("partitions:", partitions)
|
||||||
//fmt.println("block_size:", block_size)
|
//fmt.println("block_size:", block_size)
|
||||||
|
|
||||||
@@ -430,14 +442,15 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
if partition_order == 0 {
|
if partition_order == 0 {
|
||||||
num_samples = int(block_size - u16(predictor_order))
|
num_samples = int(block_size - u16(predictor_order))
|
||||||
} else if i != 0 {
|
} else if i != 0 {
|
||||||
num_samples = int(block_size / u16(math.pow2_f32(partition_order)))
|
num_samples = int(block_size / u16(pow2(partition_order)))
|
||||||
} else {
|
} else {
|
||||||
num_samples = int((block_size / u16(math.pow2_f32(partition_order))) - u16(predictor_order))
|
num_samples = int((block_size / u16(pow2(partition_order))) - u16(predictor_order))
|
||||||
}
|
}
|
||||||
|
|
||||||
if unencoded_bps == 0 {
|
if unencoded_bps == 0 {
|
||||||
for sample in 0..<num_samples {
|
for sample in 0..<num_samples {
|
||||||
append(&subframe_samples, i32(0))
|
subframe_samples[sample_i + int(predictor_order)] = 0
|
||||||
|
//append(&subframe_samples, i32(0))
|
||||||
sample_i += 1
|
sample_i += 1
|
||||||
}
|
}
|
||||||
continue lpc_partitions_loop
|
continue lpc_partitions_loop
|
||||||
@@ -449,7 +462,7 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
// NOTE: This is signed 2's complement so we check the MSB
|
// NOTE: This is signed 2's complement so we check the MSB
|
||||||
residual_sample_value := i32(read_bits(r, int(unencoded_bps)) or_return)
|
residual_sample_value := i32(read_bits(r, int(unencoded_bps)) or_return)
|
||||||
if residual_sample_value > 0 && (residual_sample_value >> (unencoded_bps - 1)) & 1 == 1 {
|
if residual_sample_value > 0 && (residual_sample_value >> (unencoded_bps - 1)) & 1 == 1 {
|
||||||
residual_sample_value = -(((~residual_sample_value) & (i32(math.pow2_f32(unencoded_bps)) - 1)) + 1)
|
residual_sample_value = -(((~residual_sample_value) & (i32(pow2(unencoded_bps)) - 1)) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore sample values using the predictor and the residual values
|
// Restore sample values using the predictor and the residual values
|
||||||
@@ -472,7 +485,8 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
|
|
||||||
sample := i32(predictor + int(residual_sample_value))
|
sample := i32(predictor + int(residual_sample_value))
|
||||||
//sample := (i32(predictor) + residual_sample_value)
|
//sample := (i32(predictor) + residual_sample_value)
|
||||||
append(&subframe_samples, sample)
|
//append(&subframe_samples, sample)
|
||||||
|
subframe_samples[sample_i + int(predictor_order)] = sample
|
||||||
//fmt.printfln(" residual[%d]=%d", sample_i, residual_sample_value)
|
//fmt.printfln(" residual[%d]=%d", sample_i, residual_sample_value)
|
||||||
//fmt.printfln(" sample[%d]=%d", sample_i, sample)
|
//fmt.printfln(" sample[%d]=%d", sample_i, sample)
|
||||||
sample_i += 1
|
sample_i += 1
|
||||||
@@ -484,16 +498,15 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
if partition_order == 0 {
|
if partition_order == 0 {
|
||||||
num_samples = int(block_size - u16(predictor_order))
|
num_samples = int(block_size - u16(predictor_order))
|
||||||
} else if i != 0 {
|
} else if i != 0 {
|
||||||
num_samples = int(block_size / u16(math.pow2_f32(partition_order)))
|
num_samples = int(block_size / u16(pow2(partition_order)))
|
||||||
} else {
|
} else {
|
||||||
num_samples = int((block_size / u16(math.pow2_f32(partition_order))) - u16(predictor_order))
|
num_samples = int((block_size / u16(pow2(partition_order))) - u16(predictor_order))
|
||||||
}
|
}
|
||||||
//fmt.printfln("reading %d samples for residual", num_samples)
|
//fmt.printfln("reading %d samples for residual", num_samples)
|
||||||
|
|
||||||
//
|
//
|
||||||
// Undo the RICE coding
|
// Undo the RICE coding
|
||||||
//
|
//
|
||||||
previous_sample_value := 0
|
|
||||||
for s in 0..<num_samples {
|
for s in 0..<num_samples {
|
||||||
quotient := 0
|
quotient := 0
|
||||||
// Read bits until we encounter a 1 (also called unary encoding). That's our quotient.
|
// Read bits until we encounter a 1 (also called unary encoding). That's our quotient.
|
||||||
@@ -505,7 +518,7 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
//fmt.println("quotient:", quotient)
|
//fmt.println("quotient:", quotient)
|
||||||
//fmt.println("remainder:", remainder)
|
//fmt.println("remainder:", remainder)
|
||||||
|
|
||||||
zigzag_encoded_value := quotient * int(math.pow2_f32(rice_parameter)) + remainder
|
zigzag_encoded_value := quotient * int(pow2(rice_parameter)) + remainder
|
||||||
|
|
||||||
// Unzigzag the residual sample values
|
// Unzigzag the residual sample values
|
||||||
residual_sample_value := zigzag_encoded_value % 2 == 0 ? zigzag_encoded_value / 2 : (zigzag_encoded_value + 1) / -2
|
residual_sample_value := zigzag_encoded_value % 2 == 0 ? zigzag_encoded_value / 2 : (zigzag_encoded_value + 1) / -2
|
||||||
@@ -529,7 +542,8 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
//fmt.printfln(" predictor[%d]=%d", sample_i, predictor)
|
//fmt.printfln(" predictor[%d]=%d", sample_i, predictor)
|
||||||
|
|
||||||
sample := (predictor + residual_sample_value)
|
sample := (predictor + residual_sample_value)
|
||||||
append(&subframe_samples, i32(sample))
|
//append(&subframe_samples, i32(sample))
|
||||||
|
subframe_samples[sample_i + int(predictor_order)] = i32(sample)
|
||||||
|
|
||||||
//fmt.printfln(" residual[%d]=%d", sample_i, residual_sample_value)
|
//fmt.printfln(" residual[%d]=%d", sample_i, residual_sample_value)
|
||||||
//fmt.printfln(" sample[%d]=%d", sample_i, sample)
|
//fmt.printfln(" sample[%d]=%d", sample_i, sample)
|
||||||
@@ -559,12 +573,13 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
for sample in 0..<predictor_order {
|
for sample in 0..<predictor_order {
|
||||||
unencoded_warmup_sample := i32(read_bits(r, bits_to_read) or_return)
|
unencoded_warmup_sample := i32(read_bits(r, bits_to_read) or_return)
|
||||||
if unencoded_warmup_sample > 0 && (unencoded_warmup_sample >> (uint(bits_to_read) - 1)) & 1 == 1 {
|
if unencoded_warmup_sample > 0 && (unencoded_warmup_sample >> (uint(bits_to_read) - 1)) & 1 == 1 {
|
||||||
unencoded_warmup_sample = -(((~unencoded_warmup_sample) & (i32(math.pow2_f32(bits_to_read)) - 1)) + 1)
|
unencoded_warmup_sample = -(((~unencoded_warmup_sample) & (i32(pow2(bits_to_read)) - 1)) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
//fmt.println("unencoded warmup sample:", unencoded_warmup_sample)
|
//fmt.println("unencoded warmup sample:", unencoded_warmup_sample)
|
||||||
//fmt.printfln("unencoded warmup sample: 0x%X", unencoded_warmup_sample)
|
//fmt.printfln("unencoded warmup sample: 0x%X", unencoded_warmup_sample)
|
||||||
append(&subframe_samples, unencoded_warmup_sample)
|
//append(&subframe_samples, unencoded_warmup_sample)
|
||||||
|
subframe_samples[sample] = unencoded_warmup_sample
|
||||||
}
|
}
|
||||||
|
|
||||||
residual_coding_method := ResidualCodingMethod(read_bits(r, 2) or_return)
|
residual_coding_method := ResidualCodingMethod(read_bits(r, 2) or_return)
|
||||||
@@ -575,7 +590,7 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
|
|
||||||
partition_order := read_bits(r, 4) or_return
|
partition_order := read_bits(r, 4) or_return
|
||||||
//fmt.println("parition order", partition_order)
|
//fmt.println("parition order", partition_order)
|
||||||
partitions := int(math.pow2_f32(partition_order))
|
partitions := int(pow2(partition_order))
|
||||||
//fmt.println("partitions:", partitions)
|
//fmt.println("partitions:", partitions)
|
||||||
//fmt.println("block_size:", block_size)
|
//fmt.println("block_size:", block_size)
|
||||||
|
|
||||||
@@ -589,15 +604,16 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
if partition_order == 0 {
|
if partition_order == 0 {
|
||||||
num_samples = int(block_size - u16(predictor_order))
|
num_samples = int(block_size - u16(predictor_order))
|
||||||
} else if i != 0 {
|
} else if i != 0 {
|
||||||
num_samples = int(block_size / u16(math.pow2_f32(partition_order)))
|
num_samples = int(block_size / u16(pow2(partition_order)))
|
||||||
} else {
|
} else {
|
||||||
num_samples = int((block_size / u16(math.pow2_f32(partition_order))) - u16(predictor_order))
|
num_samples = int((block_size / u16(pow2(partition_order))) - u16(predictor_order))
|
||||||
}
|
}
|
||||||
|
|
||||||
if unencoded_bps == 0 {
|
if unencoded_bps == 0 {
|
||||||
for sample in 0..<num_samples {
|
for sample in 0..<num_samples {
|
||||||
sample_i += 1
|
//append(&subframe_samples, i32(0))
|
||||||
append(&subframe_samples, i32(0))
|
subframe_samples[sample_i + int(predictor_order)] = 0
|
||||||
|
sample_i += 1
|
||||||
}
|
}
|
||||||
continue fixed_partitions_loop
|
continue fixed_partitions_loop
|
||||||
}
|
}
|
||||||
@@ -608,7 +624,7 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
// NOTE: This is signed 2's complement so we check the MSB
|
// NOTE: This is signed 2's complement so we check the MSB
|
||||||
residual_sample_value := i8(read_bits(r, int(unencoded_bps)) or_return)
|
residual_sample_value := i8(read_bits(r, int(unencoded_bps)) or_return)
|
||||||
if residual_sample_value > 0 && (residual_sample_value >> (unencoded_bps - 1)) & 1 == 1 {
|
if residual_sample_value > 0 && (residual_sample_value >> (unencoded_bps - 1)) & 1 == 1 {
|
||||||
residual_sample_value = -(((~residual_sample_value) & (i8(math.pow2_f32(unencoded_bps)) - 1)) + 1)
|
residual_sample_value = -(((~residual_sample_value) & (i8(pow2(unencoded_bps)) - 1)) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
//fmt.printfln(" residual[%d]=%d", sample_i, residual_sample_value)
|
//fmt.printfln(" residual[%d]=%d", sample_i, residual_sample_value)
|
||||||
@@ -625,9 +641,9 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
if partition_order == 0 {
|
if partition_order == 0 {
|
||||||
num_samples = int(block_size - u16(predictor_order))
|
num_samples = int(block_size - u16(predictor_order))
|
||||||
} else if i != 0 {
|
} else if i != 0 {
|
||||||
num_samples = int(block_size / u16(math.pow2_f32(partition_order)))
|
num_samples = int(block_size / u16(pow2(partition_order)))
|
||||||
} else {
|
} else {
|
||||||
num_samples = int((block_size / u16(math.pow2_f32(partition_order))) - u16(predictor_order))
|
num_samples = int((block_size / u16(pow2(partition_order))) - u16(predictor_order))
|
||||||
}
|
}
|
||||||
//fmt.printfln("reading %d samples for residual", samples)
|
//fmt.printfln("reading %d samples for residual", samples)
|
||||||
|
|
||||||
@@ -645,7 +661,7 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
//fmt.println("quotient:", quotient)
|
//fmt.println("quotient:", quotient)
|
||||||
//fmt.println("remainder:", remainder)
|
//fmt.println("remainder:", remainder)
|
||||||
|
|
||||||
zigzag_encoded_value := quotient * int(math.pow2_f32(rice_parameter)) + remainder
|
zigzag_encoded_value := quotient * int(pow2(rice_parameter)) + remainder
|
||||||
|
|
||||||
// Unzigzag the residual sample values
|
// Unzigzag the residual sample values
|
||||||
residual_sample_value := zigzag_encoded_value % 2 == 0 ? zigzag_encoded_value / 2 : (zigzag_encoded_value + 1) / -2
|
residual_sample_value := zigzag_encoded_value % 2 == 0 ? zigzag_encoded_value / 2 : (zigzag_encoded_value + 1) / -2
|
||||||
@@ -672,7 +688,8 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
|
|
||||||
//sample_value := residual_sample_value + (predictor_order == 0 ? 0 : int(subframe_samples[sample_i]))
|
//sample_value := residual_sample_value + (predictor_order == 0 ? 0 : int(subframe_samples[sample_i]))
|
||||||
|
|
||||||
append(&subframe_samples, i32(sample_value))
|
//append(&subframe_samples, i32(sample_value))
|
||||||
|
subframe_samples[sample_i + int(predictor_order)] = i32(sample_value)
|
||||||
|
|
||||||
sample_i += 1
|
sample_i += 1
|
||||||
|
|
||||||
@@ -695,7 +712,7 @@ decode_subframe :: proc(r: ^Reader, bps: u8, block_size: u16) -> (samples: []i32
|
|||||||
// TODO: remove
|
// TODO: remove
|
||||||
frame_num := 0
|
frame_num := 0
|
||||||
|
|
||||||
decode_frame :: proc(r: ^Reader, streaminfo_bps: u8, streaminfo_sample_rate: u32, channels: u8) -> (err: Error) {
|
decode_frame :: proc(r: ^Reader, streaminfo_bps: u8, streaminfo_sample_rate: u32, channels: u8) -> (err: Error) #no_bounds_check {
|
||||||
//
|
//
|
||||||
// Frame Header
|
// Frame Header
|
||||||
//
|
//
|
||||||
@@ -742,13 +759,13 @@ decode_frame :: proc(r: ^Reader, streaminfo_bps: u8, streaminfo_sample_rate: u32
|
|||||||
case 1:
|
case 1:
|
||||||
actual_block_size = 192
|
actual_block_size = 192
|
||||||
case 2..=5:
|
case 2..=5:
|
||||||
actual_block_size = 576 * auto_cast (math.pow2_f32(block_size - 2))
|
actual_block_size = 576 * auto_cast (pow2(block_size - 2))
|
||||||
case 6:
|
case 6:
|
||||||
actual_block_size = auto_cast (read_byte(r) or_return) + 1
|
actual_block_size = auto_cast (read_byte(r) or_return) + 1
|
||||||
case 7:
|
case 7:
|
||||||
actual_block_size = (read_data(r, u16be) or_return) + 1
|
actual_block_size = (read_data(r, u16be) or_return) + 1
|
||||||
case 8..=15:
|
case 8..=15:
|
||||||
actual_block_size = 256 * auto_cast (math.pow2_f32(block_size - 8))
|
actual_block_size = 256 * auto_cast (pow2(block_size - 8))
|
||||||
case:
|
case:
|
||||||
return .Invalid_Block_Size
|
return .Invalid_Block_Size
|
||||||
}
|
}
|
||||||
@@ -945,29 +962,27 @@ decode_frame :: proc(r: ^Reader, streaminfo_bps: u8, streaminfo_sample_rate: u32
|
|||||||
switch bps {
|
switch bps {
|
||||||
case 1..=8:
|
case 1..=8:
|
||||||
data := []u8{u8(sample)}
|
data := []u8{u8(sample)}
|
||||||
os.write(output_file, data)
|
//os.write(output_file, data)
|
||||||
md5.update(&md5_ctx, data)
|
md5.update(&md5_ctx, data)
|
||||||
case 9..=16:
|
case 9..=16:
|
||||||
first_byte := i8(sample & 0xFF)
|
first_byte := i8(sample & 0xFF)
|
||||||
second_byte := i8((sample >> 8) & 0xFF)
|
second_byte := i8((sample >> 8) & 0xFF)
|
||||||
data := slice.reinterpret([]u8, []i8{first_byte, second_byte})
|
data := []u8{u8(first_byte), u8(second_byte)}
|
||||||
os.write(output_file, data)
|
//data := slice.reinterpret([]u8, []i8{first_byte, second_byte})
|
||||||
|
//os.write(output_file, data)
|
||||||
md5.update(&md5_ctx, data)
|
md5.update(&md5_ctx, data)
|
||||||
case 17..=24:
|
case 17..=24:
|
||||||
first_byte := i8(sample & 0xFF)
|
first_byte := i8(sample & 0xFF)
|
||||||
second_byte := i8((sample >> 8) & 0xFF)
|
second_byte := i8((sample >> 8) & 0xFF)
|
||||||
third_byte := i8((sample >> 16) & 0xFF)
|
third_byte := i8((sample >> 16) & 0xFF)
|
||||||
data := slice.reinterpret([]u8, []i8{first_byte, second_byte, third_byte})
|
data := []u8{u8(first_byte), u8(second_byte), u8(third_byte)}
|
||||||
os.write(output_file, data)
|
//data := slice.reinterpret([]u8, []i8{first_byte, second_byte, third_byte})
|
||||||
|
//os.write(output_file, data)
|
||||||
md5.update(&md5_ctx, data)
|
md5.update(&md5_ctx, data)
|
||||||
case 25..=32:
|
case 25..=32:
|
||||||
first_byte := i8(sample & 0xFF)
|
data := transmute([4]u8)sample
|
||||||
second_byte := i8((sample >> 8) & 0xFF)
|
//os.write(output_file, data[:])
|
||||||
third_byte := i8((sample >> 16) & 0xFF)
|
md5.update(&md5_ctx, data[:])
|
||||||
fourth_byte := i8((sample >> 24) & 0xFF)
|
|
||||||
data := slice.reinterpret([]u8, []i8{first_byte, second_byte, third_byte, fourth_byte})
|
|
||||||
os.write(output_file, data)
|
|
||||||
md5.update(&md5_ctx, data)
|
|
||||||
case:
|
case:
|
||||||
fmt.println("INVALID BPS")
|
fmt.println("INVALID BPS")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
@@ -1192,17 +1207,17 @@ load_from_bytes :: proc(data: []byte, allocator := context.allocator) -> (err: E
|
|||||||
}
|
}
|
||||||
case .PICTURE:
|
case .PICTURE:
|
||||||
// TODO: save the pic data into a struct
|
// TODO: save the pic data into a struct
|
||||||
// TODO: maybe put all of these into a struct so we do one big read?
|
|
||||||
pic_type := read_data(&r, PictureType) or_return
|
pic_type := read_data(&r, PictureType) or_return
|
||||||
mime_len := read_data(&r, u32be) or_return
|
mime_len := read_data(&r, u32be) or_return
|
||||||
mimetype := string(read_slice(&r, auto_cast mime_len) or_return)
|
mimetype := string(read_slice(&r, auto_cast mime_len) or_return)
|
||||||
desc_len := read_data(&r, u32be) or_return
|
desc_len := read_data(&r, u32be) or_return
|
||||||
desc := string(read_slice(&r, auto_cast desc_len) or_return)
|
desc := string(read_slice(&r, auto_cast desc_len) or_return)
|
||||||
width := read_data(&r, u32be) or_return
|
metadata := read_data(&r, PictureMetadata) or_return
|
||||||
height := read_data(&r, u32be) or_return
|
width := metadata.width
|
||||||
depth := read_data(&r, u32be) or_return
|
height := metadata.height
|
||||||
num_colors := read_data(&r, u32be) or_return
|
depth := metadata.depth
|
||||||
data_len := read_data(&r, u32be) or_return
|
num_colors := metadata.num_colors
|
||||||
|
data_len := metadata.data_len
|
||||||
data := read_slice(&r, auto_cast data_len) or_return
|
data := read_slice(&r, auto_cast data_len) or_return
|
||||||
//fmt.println(pic_type)
|
//fmt.println(pic_type)
|
||||||
//fmt.println(mimetype)
|
//fmt.println(mimetype)
|
||||||
@@ -1250,8 +1265,8 @@ load_from_bytes :: proc(data: []byte, allocator := context.allocator) -> (err: E
|
|||||||
load_from_file :: proc(filename: string, allocator := context.allocator) -> (err: Error) {
|
load_from_file :: proc(filename: string, allocator := context.allocator) -> (err: Error) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
output_file, _ = os.open("output.raw", os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0o664)
|
//output_file, _ = os.open("output.raw", os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0o664)
|
||||||
defer os.close(output_file)
|
//defer os.close(output_file)
|
||||||
|
|
||||||
data, ok := os.read_entire_file(filename)
|
data, ok := os.read_entire_file(filename)
|
||||||
defer delete(data)
|
defer delete(data)
|
||||||
|
|||||||
+72
-21
@@ -3,14 +3,13 @@ package flac
|
|||||||
|
|
||||||
import "core:bytes"
|
import "core:bytes"
|
||||||
import "core:io"
|
import "core:io"
|
||||||
import "core:math"
|
|
||||||
|
|
||||||
/* Basic byte reader with support for reading bits.
|
/* Basic byte reader with support for reading bits.
|
||||||
Uses core:bytes reader under the hood with a few useful procedures for reading structs and other types.
|
Uses core:bytes reader under the hood with a few useful procedures for reading structs and other types.
|
||||||
*/
|
*/
|
||||||
Reader :: struct {
|
Reader :: struct {
|
||||||
using _: bytes.Reader,
|
using _: bytes.Reader,
|
||||||
bits_read_in_byte: u8,
|
bits_read: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
read_slice :: #force_inline proc(r: ^Reader, size: int) -> (res: []u8, err: io.Error) {
|
read_slice :: #force_inline proc(r: ^Reader, size: int) -> (res: []u8, err: io.Error) {
|
||||||
@@ -37,43 +36,95 @@ read_data :: #force_inline proc(r: ^Reader, $T: typeid) -> (res: T, err: io.Erro
|
|||||||
return (^T)(&b[0])^, nil
|
return (^T)(&b[0])^, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
read_bit :: #force_inline proc(r: ^Reader) -> (bit: byte, err: Error) {
|
pow2 :: #force_inline proc(#any_int exp: uint) -> int {
|
||||||
|
return 1 << exp
|
||||||
|
}
|
||||||
|
|
||||||
|
read_bit :: proc(r: ^Reader) -> (bit: byte, err: Error) #no_bounds_check {
|
||||||
if r.i >= i64(len(r.s)) {
|
if r.i >= i64(len(r.s)) {
|
||||||
return 0, .EOF
|
return 0, .EOF
|
||||||
}
|
}
|
||||||
byte := r.s[r.i]
|
|
||||||
|
|
||||||
// Get the bit that's after however many bits read starting from the MSB in the byte
|
bits := 8 - (r.bits_read + 1)
|
||||||
bits := 8 - (r.bits_read_in_byte + 1)
|
b := (r.s[r.i] >> bits) & 1
|
||||||
b := (r.s[r.i:r.i+1][0] & auto_cast math.pow2_f32(bits)) >> bits
|
r.bits_read += 1
|
||||||
r.bits_read_in_byte += 1
|
|
||||||
|
|
||||||
if r.bits_read_in_byte == 8 {
|
if r.bits_read == 8 {
|
||||||
r.i += 1
|
r.i += 1
|
||||||
r.bits_read_in_byte = 0
|
r.bits_read = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
read_bits :: proc(r: ^Reader, n: int) -> (bits: u64, err: Error) {
|
//read_bits :: proc(r: ^Reader, n: int) -> (bits: u64, err: Error) {
|
||||||
x: u64 = 0
|
// x: u64 = 0
|
||||||
|
//
|
||||||
|
// for i in 0 ..< n {
|
||||||
|
// x = 2 * x + auto_cast read_bit(r) or_return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return x, nil
|
||||||
|
//}
|
||||||
|
|
||||||
for i in 0 ..< n {
|
// TODO: optimize this even more
|
||||||
x = 2 * x + auto_cast read_bit(r) or_return
|
read_bits :: proc(r: ^Reader, n: int) -> (bits: u64, err: Error) #no_bounds_check {
|
||||||
}
|
|
||||||
|
|
||||||
return x, nil
|
//if n % 8 == 0 {
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
//if r.bits_remaining < u8(n) {
|
||||||
|
// // we need to read into the next byte too and possibly more bytes
|
||||||
|
//} else if r.bits_remaining == u8(n) {
|
||||||
|
// r.bits_remaining = 0
|
||||||
|
// r.i += 1
|
||||||
|
//} else {
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
n := n
|
||||||
|
for n > 0 {
|
||||||
|
if r.i >= i64(len(r.s)) {
|
||||||
|
return 0, .EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
to_read := min(n, 8-int(r.bits_read))
|
||||||
|
mask := (1 << u8(to_read)) - 1
|
||||||
|
shift := 8 - int(r.bits_read) - to_read
|
||||||
|
|
||||||
|
// Extract bits from the current byte
|
||||||
|
bitsPart := u64(r.s[r.i] >> u8(shift)) & u64(mask)
|
||||||
|
bits |= bitsPart << u64(n - to_read)
|
||||||
|
|
||||||
|
// Update counters
|
||||||
|
r.bits_read += u8(to_read)
|
||||||
|
n -= to_read
|
||||||
|
|
||||||
|
// Move to the next byte if all bits in the current byte have been read
|
||||||
|
if r.bits_read == 8 {
|
||||||
|
r.i += 1
|
||||||
|
r.bits_read = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bits, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
read_byte :: proc(r: ^Reader) -> (b: byte, err: Error) {
|
read_byte :: proc(r: ^Reader) -> (b: byte, err: Error) #no_bounds_check {
|
||||||
if r.i >= i64(len(r.s)) {
|
if r.i >= i64(len(r.s)) {
|
||||||
return 0, .EOF
|
return 0, .EOF
|
||||||
}
|
}
|
||||||
// Continue reading from the current byte if it has unread bits.
|
// Continue reading from the current byte if it has unread bits.
|
||||||
// Needed for the subframes.
|
// Needed for the subframes.
|
||||||
if r.bits_read_in_byte != 0 {
|
if r.bits_read != 0 {
|
||||||
b = u8(read_bits(r, 8) or_return)
|
cur_byte := r.s[r.i]
|
||||||
|
next_byte := r.s[r.i + 1]
|
||||||
|
rem_bits := 8 - r.bits_read
|
||||||
|
rem_bits_mask: u8 = (1 << rem_bits) - 1
|
||||||
|
b = ((cur_byte & rem_bits_mask) << r.bits_read) | (next_byte >> rem_bits)
|
||||||
|
r.i += 1
|
||||||
} else {
|
} else {
|
||||||
b = r.s[r.i]
|
b = r.s[r.i]
|
||||||
r.i += 1
|
r.i += 1
|
||||||
@@ -82,7 +133,7 @@ read_byte :: proc(r: ^Reader) -> (b: byte, err: Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
align_to_byte :: proc(r: ^Reader) -> Error {
|
align_to_byte :: proc(r: ^Reader) -> Error {
|
||||||
if r.bits_read_in_byte == 0 {
|
if r.bits_read == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if r.i >= i64(len(r.s)) {
|
if r.i >= i64(len(r.s)) {
|
||||||
@@ -90,7 +141,7 @@ align_to_byte :: proc(r: ^Reader) -> Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Align by skipping the remaining bits in the byte
|
// Align by skipping the remaining bits in the byte
|
||||||
r.bits_read_in_byte = 0
|
r.bits_read = 0
|
||||||
r.i += 1
|
r.i += 1
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user