diff --git a/examples/buffered/main.odin b/examples/buffered/main.odin index a642797..e4c016e 100644 --- a/examples/buffered/main.odin +++ b/examples/buffered/main.odin @@ -77,12 +77,14 @@ main :: proc() { // } //} + // 8 bps audio //converted_samples := make([]u8, len(samples)) //defer delete(converted_samples) //for sample, i in samples { // converted_samples[i] = u8(sample & 0xFF) //} + // 16 bps audio converted_samples := make([]i16, len(frame.samples)) defer delete(converted_samples) for sample, i in frame.samples { diff --git a/examples/in_memory/main.odin b/examples/in_memory/main.odin index 9ead040..6f76618 100644 --- a/examples/in_memory/main.odin +++ b/examples/in_memory/main.odin @@ -33,6 +33,7 @@ main :: proc() { fmt.eprintln("Failed to initialize audio device: ", alsa.strerror(alsa_err)) os.exit(1) } + defer alsa.pcm_close(handle) start := time.now() flac_data, err := flac.load_from_file(os.args[1], allocator = allocator) @@ -55,6 +56,7 @@ main :: proc() { } converted_samples := make([]i16, len(flac_data.samples)) + defer delete(converted_samples) for sample, i in flac_data.samples { new_sample := sample & 0xFF @@ -73,7 +75,6 @@ main :: proc() { if alsa_err < 0 { fmt.eprintln("pcm_drain failed with:", alsa.strerror(alsa_err)) } - alsa.pcm_close(handle) elapsed := time.diff(start, end) fmt.println("Decoding took", elapsed) diff --git a/flac.odin b/flac.odin index c7d1ea2..1987bd3 100644 --- a/flac.odin +++ b/flac.odin @@ -23,8 +23,8 @@ FlacError :: enum { Invalid_Coefficient_Precision, CRC_Mismatch, MD5_Mismatch, - Unsupported_BPS, // Remove when implemented - Unencoded_BPS_For_Fixed_Subframe_Is_Unsupported, // Remove when implemented + Unsupported_BPS, // TODO: Remove when implemented + Unencoded_BPS_For_Fixed_Subframe_Is_Unsupported, // TODO: Remove when implemented Invalid_Residual_Coding_Method, Invalid_Block_Size, Bits_Per_Second_Mismatch, @@ -40,12 +40,12 @@ Option: Returns all metadata of a FLAC stream without decoding the audio data. */ -Option :: enum { +Option :: enum u8 { skip_md5_check, only_return_metadata, } -Options :: bit_set[Option] +Options :: bit_set[Option; u8] PictureType :: enum u32 { OTHER, @@ -73,6 +73,9 @@ PictureType :: enum u32 { Flac :: struct { metadata: FlacMetadata, + // When using the in-memory API this will hold all the decoded samples of the FLAC stream. + // When using the buffered API this will hold the samples up to the currently decoded frame. If all frames have + // been decoded then this will hold all the decoded samples. samples: [dynamic]i32, } @@ -102,6 +105,8 @@ Picture :: struct { Frame :: struct { channels: u8, sample_rate: u32, + // A slice of `Flac`'s `samples` field. + // Contains the frame's decoded samples. samples: []i32, } @@ -720,7 +725,7 @@ read_metadata :: proc(r: ^Reader, buffered := false, allocator := context.alloca length = u32(md_block_hdr & 0xFFFFFF), } - last_block = cast(bool)(metadata_block_header.last_block) + last_block = metadata_block_header.last_block switch metadata_block_header.type { case .STREAMINFO: @@ -861,12 +866,16 @@ read_next_frame :: proc(r: ^Reader, flac: ^Flac, allocator := context.allocator) crc_buffer: Buffer // NOTE: using the default heap allocator here causes a use-after-free bug on files subset/05, subset/06, and subset/25 - // No idea what the cause of the bug is. I am inclined to believe that it's a bug of the default heap allocator but - // maybe my code is fucking up the memory so bad it makes it seems that way. + // No idea what the cause of the bug is. + // + // Resolved without understanding the root issue. See below code for a note on this. buffer_init_allocator(&crc_buffer, 0, 128) + defer buffer_destroy(&crc_buffer) crc := buffer_to_stream(&crc_buffer) r := &Reader{ + // TODO: tee reader's docs say we should call io.destroy() when done with it. But the tee reader + // doesn't implement the .Destroy method so it does absolutely nothing ?? Should ask about this in the discord. r = io.tee_reader_init(&tee_r, r, crc), buf = r.buf, x = r.x, @@ -1049,12 +1058,13 @@ read_next_frame :: proc(r: ^Reader, flac: ^Flac, allocator := context.allocator) correlate(subframes, channel_assignment) - samples_arr := make([dynamic]i32, 0, block_size * 2) + start := len(flac.samples) + // Write the samples interleaved. for i in 0.. Error { calculated_md5 := [16]byte{} md5.final(md5_ctx, calculated_md5[:]) diff --git a/internal.odin b/internal.odin index 318be91..f503bcf 100644 --- a/internal.odin +++ b/internal.odin @@ -1,4 +1,4 @@ -//+private +#+private package flac import "core:crypto/legacy/md5" diff --git a/reader.odin b/reader.odin index 074f62c..63e2583 100644 --- a/reader.odin +++ b/reader.odin @@ -1,7 +1,6 @@ -//+private +#+private package flac -import "core:bytes" import "core:io" /* Basic byte and bit reader. @@ -24,6 +23,7 @@ read_slice :: #force_inline proc(r: ^Reader, buf: []u8) -> io.Error { } read_data :: #force_inline proc(r: ^Reader, $T: typeid) -> (res: T, err: io.Error) { + // b is safe to return here because the proc is always inlined. b: [size_of(T)]byte read_slice(r, b[:]) or_return diff --git a/tests/flac_buffered_test.odin b/tests/flac_buffered_test.odin index fbeb1c1..ed6e152 100644 --- a/tests/flac_buffered_test.odin +++ b/tests/flac_buffered_test.odin @@ -13,7 +13,6 @@ test_blocksize_4096_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -29,7 +28,6 @@ test_blocksize_4608_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -45,7 +43,6 @@ test_blocksize_16_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -61,7 +58,6 @@ test_blocksize_192_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -77,7 +73,6 @@ test_blocksize_254_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -93,7 +88,6 @@ test_blocksize_512_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -109,7 +103,6 @@ test_blocksize_725_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -125,7 +118,6 @@ test_blocksize_1000_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -141,7 +133,6 @@ test_blocksize_1937_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -157,7 +148,6 @@ test_blocksize_2304_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -173,7 +163,6 @@ test_partition_order_8_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -189,7 +178,6 @@ test_qlp_precision_15_bit_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -205,7 +193,6 @@ test_qlp_precision_2_bit_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -221,7 +208,6 @@ wasted_bits_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -237,7 +223,6 @@ only_verbatim_subframes_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -257,7 +242,6 @@ partition_order_8_containing_escaped_partitions_buffered :: proc(t: ^testing.T) for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -273,7 +257,6 @@ all_fixed_orders_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -289,7 +272,6 @@ precision_search_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -305,7 +287,6 @@ samplerate_35467Hz_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -321,7 +302,6 @@ samplerate_39kHz_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -337,7 +317,6 @@ samplerate_22050Hz_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -353,7 +332,6 @@ _12_bit_per_sample_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -369,7 +347,6 @@ _8_bit_per_sample_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -391,7 +368,6 @@ variable_blocksize_file_created_with_flake_revision_264_buffered :: proc(t: ^tes for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -416,7 +392,6 @@ variable_blocksize_file_created_with_flake_revision_264_modified_to_create_small for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -438,7 +413,6 @@ variable_blocksize_file_created_with_CUETools_Flake_2_1_6_buffered :: proc(t: ^t for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -460,7 +434,6 @@ old_format_variable_blocksize_file_created_with_Flake_0_11_buffered :: proc(t: ^ for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -476,7 +449,6 @@ high_resolution_audio_default_settings_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -492,7 +464,6 @@ high_resolution_audio_blocksize_16384_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -508,7 +479,6 @@ high_resolution_audio_blocksize_13456_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -530,7 +500,6 @@ high_resolution_audio_using_only_32nd_order_predictors_buffered :: proc(t: ^test for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -552,7 +521,6 @@ high_resolution_audio_partition_order_8_containing_escaped_partitions_buffered : for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -568,7 +536,6 @@ samplerate_192kHz_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -588,7 +555,6 @@ samplerate_192kHz_using_only_32nd_order_predictors_buffered :: proc(t: ^testing. for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -604,7 +570,6 @@ samplerate_134560Hz_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -620,7 +585,6 @@ samplerate_384kHz_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -636,7 +600,6 @@ _20_bit_per_sample_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -652,7 +615,6 @@ _3_channels_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -668,7 +630,6 @@ _4_channels_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -684,7 +645,6 @@ _5_channels_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -700,7 +660,6 @@ _6_channels_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -716,7 +675,6 @@ _7_channels_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -732,7 +690,6 @@ _8_channels_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -754,7 +711,6 @@ _8_channel_surround_192kHz_24_bit_using_only_32nd_order_predictors_buffered :: p for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -770,7 +726,6 @@ no_total_number_of_samples_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -786,7 +741,6 @@ no_min_max_framesize_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -802,7 +756,6 @@ only_streaminfo_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -818,7 +771,6 @@ extreme_large_seektable_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -834,7 +786,6 @@ extreme_large_padding_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -850,7 +801,6 @@ extreme_large_picture_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -866,7 +816,6 @@ extreme_large_vorbiscomment_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -882,7 +831,6 @@ extreme_large_application_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -898,7 +846,6 @@ cuesheet_with_very_many_indexes_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -914,7 +861,6 @@ _1000x_repeating_vorbiscomment_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -930,7 +876,6 @@ file_48_53_combined_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -946,7 +891,6 @@ jpg_picture_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -962,7 +906,6 @@ png_picture_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -978,7 +921,6 @@ gif_picture_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -994,7 +936,6 @@ avif_picture_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -1010,7 +951,6 @@ mono_audio_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -1026,7 +966,6 @@ predictor_overflow_check_16_bit_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -1042,7 +981,6 @@ predictor_overflow_check_20_bit_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -1058,7 +996,6 @@ predictor_overflow_check_24_bit_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -1074,7 +1011,6 @@ rice_partitions_with_escape_code_zero_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -1090,7 +1026,6 @@ uncommon_32_bit_per_sample_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break } @@ -1106,7 +1041,6 @@ uncommon_samplerate_768kHz_buffered :: proc(t: ^testing.T) { for { frame, f_err := flac.read_next_frame(r, data) - defer delete(frame.samples) if f_err == .EOF { break }