Compare commits

..
3 Commits
5 changed files with 197 additions and 107 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
package flac_linux_example package flac_linux_alsa_example
import "core:fmt" import "core:fmt"
import "core:mem" import "core:mem"
+98 -35
View File
@@ -5,8 +5,7 @@ import "core:crypto/legacy/md5"
import "core:fmt" import "core:fmt"
import "core:io" import "core:io"
import "core:mem" import "core:mem"
import "core:os/os2" import "core:os"
import "core:time"
Error :: union { Error :: union {
io.Error, io.Error,
@@ -69,6 +68,7 @@ PictureType :: enum u32 {
Flac :: struct { Flac :: struct {
metadata: FlacMetadata, metadata: FlacMetadata,
// This holds the samples of the current frame. // This holds the samples of the current frame.
// TODO: Should this be deleted? every frame already holds its own samples data
samples: [dynamic]i32, samples: [dynamic]i32,
} }
@@ -429,7 +429,16 @@ correlate :: proc(subframes: [][]i32, channel_assignment: ChannelAssignment) {
} }
@(private) @(private)
read_metadata :: proc(r: ^Reader, allocator := context.allocator) -> (flac: ^Flac, err: Error) { read_metadata :: proc(r: ^Reader, allocator := context.allocator) -> (out_flac: ^Flac, err: Error) {
context.allocator = allocator
/* Held in a local rather than in the named result: an Odin `defer` cannot
change a named result, so the unwind below is able to free this but not to
nil it out for the caller. Assigning it only on the successful return means
every error path hands back nil instead of a freed pointer.
*/
flac: ^Flac
header := read_data(r, FlacHeader) or_return header := read_data(r, FlacHeader) or_return
if header.magic != FLAC_MAGIC { if header.magic != FLAC_MAGIC {
return nil, .Invalid_Signature return nil, .Invalid_Signature
@@ -453,7 +462,7 @@ read_metadata :: proc(r: ^Reader, allocator := context.allocator) -> (flac: ^Fla
} }
if streaminfo_header.type != .STREAMINFO { if streaminfo_header.type != .STREAMINFO {
return flac, .Missing_StreamInfo return nil, .Missing_StreamInfo
} }
if flac == nil { if flac == nil {
@@ -467,6 +476,30 @@ read_metadata :: proc(r: ^Reader, allocator := context.allocator) -> (flac: ^Fla
flac.metadata.expected_md5 = header.streaminfo.md5 flac.metadata.expected_md5 = header.streaminfo.md5
pictures := make([dynamic]Picture, 0, 2, allocator) pictures := make([dynamic]Picture, 0, 2, allocator)
/* Everything allocated from here on hangs off `flac`, and a caller that gets
an error back is handed a nil `flac` -- so it has nothing to pass to
`destroy` and cannot clean any of this up itself. Unwind it here instead.
Each block below therefore hands its allocations to `flac` or to `pictures`
as soon as they exist, before the next read that could fail.
*/
defer if err != nil {
for picture in pictures {
delete(picture.mimetype)
delete(picture.description)
delete(picture.data)
}
delete(pictures)
for comment in flac.metadata.vorbis_comments {
delete(comment)
}
delete(flac.metadata.vorbis_comments)
delete(flac.metadata.vendor_name)
free(flac)
}
last_block := streaminfo_header.last_block last_block := streaminfo_header.last_block
for !last_block { for !last_block {
md_block_hdr := read_data(r, u32be) or_return md_block_hdr := read_data(r, u32be) or_return
@@ -506,26 +539,33 @@ read_metadata :: proc(r: ^Reader, allocator := context.allocator) -> (flac: ^Fla
fmt.eprintfln("Expected size: %d, Got %d", metadata_block_header.length, actual_size) fmt.eprintfln("Expected size: %d, Got %d", metadata_block_header.length, actual_size)
} }
case .VORBIS_COMMENT: case .VORBIS_COMMENT:
// A stream may carry more than one of these; the last one wins,
// so release the previous block rather than orphaning it.
for comment in flac.metadata.vorbis_comments {
delete(comment)
}
delete(flac.metadata.vorbis_comments)
delete(flac.metadata.vendor_name)
flac.metadata.vorbis_comments = nil
flac.metadata.vendor_name = ""
vendor_name_len := read_data(r, u32le) or_return vendor_name_len := read_data(r, u32le) or_return
vendor_name_slice := make([]byte, vendor_name_len) vendor_name_slice := make([]byte, vendor_name_len)
flac.metadata.vendor_name = string(vendor_name_slice)
read_slice(r, vendor_name_slice) or_return read_slice(r, vendor_name_slice) or_return
vendor_name := string(vendor_name_slice)
user_comment_list_len := read_data(r, u32le) or_return user_comment_list_len := read_data(r, u32le) or_return
actual_size := 4 + vendor_name_len + 4 actual_size := 4 + vendor_name_len + 4
comments := make([]string, user_comment_list_len) comments := make([]string, user_comment_list_len)
flac.metadata.vorbis_comments = comments
for i in 0..<user_comment_list_len { for i in 0..<user_comment_list_len {
comment_len := read_data(r, u32le) or_return comment_len := read_data(r, u32le) or_return
comment_slice := make([]byte, comment_len) comment_slice := make([]byte, comment_len)
comments[i] = string(comment_slice)
read_slice(r, comment_slice) or_return read_slice(r, comment_slice) or_return
comment := string(comment_slice)
actual_size += 4 + comment_len actual_size += 4 + comment_len
comments[i] = comment
} }
flac.metadata.vorbis_comments = comments
flac.metadata.vendor_name = vendor_name
if metadata_block_header.length != u32(actual_size) { if metadata_block_header.length != u32(actual_size) {
fmt.eprintln("Vorbis metadata header length mismatch!") fmt.eprintln("Vorbis metadata header length mismatch!")
fmt.eprintfln("Expected size: %d, Got %d", metadata_block_header.length, actual_size) fmt.eprintfln("Expected size: %d, Got %d", metadata_block_header.length, actual_size)
@@ -537,7 +577,7 @@ read_metadata :: proc(r: ^Reader, allocator := context.allocator) -> (flac: ^Fla
cuesheet := read_data(r, CueSheet) or_return cuesheet := read_data(r, CueSheet) or_return
if cuesheet.num_tracks < 1 { if cuesheet.num_tracks < 1 {
// TODO: should this be a warning instead of an error that halts the decoding? // TODO: should this be a warning instead of an error that halts the decoding?
return flac, .Missing_Lead_Out_Track return nil, .Missing_Lead_Out_Track
} }
//fmt.println(cuesheet) //fmt.println(cuesheet)
for i in 0..<cuesheet.num_tracks { for i in 0..<cuesheet.num_tracks {
@@ -551,15 +591,20 @@ read_metadata :: proc(r: ^Reader, allocator := context.allocator) -> (flac: ^Fla
case .PICTURE: case .PICTURE:
pic_type := PictureType(read_data(r, u32be) or_return) pic_type := PictureType(read_data(r, u32be) or_return)
mime_len := read_data(r, u32be) or_return mime_len := read_data(r, u32be) or_return
// These three are only reachable through `pictures` once the
// append below runs, so they need their own unwind until then.
mimetype_slice := make([]byte, mime_len) mimetype_slice := make([]byte, mime_len)
defer if err != nil {delete(mimetype_slice)}
read_slice(r, mimetype_slice) or_return read_slice(r, mimetype_slice) or_return
mimetype := string(mimetype_slice) mimetype := string(mimetype_slice)
desc_len := read_data(r, u32be) or_return desc_len := read_data(r, u32be) or_return
desc_slice := make([]byte, desc_len) desc_slice := make([]byte, desc_len)
defer if err != nil {delete(desc_slice)}
read_slice(r, desc_slice) or_return read_slice(r, desc_slice) or_return
desc := string(desc_slice) desc := string(desc_slice)
metadata := read_data(r, PictureMetadata) or_return metadata := read_data(r, PictureMetadata) or_return
data := make([]byte, metadata.data_len) data := make([]byte, metadata.data_len)
defer if err != nil {delete(data)}
read_slice(r, data) or_return read_slice(r, data) or_return
picture := Picture{ picture := Picture{
type = pic_type, type = pic_type,
@@ -869,33 +914,47 @@ md5sum :: proc(md5_ctx: ^md5.Context, flac: ^Flac) -> Error {
} }
// `load_from_file` initializes a buffered reader for the file and reads all the metadata blocks. // `load_from_file` initializes a buffered reader for the file and reads all the metadata blocks.
// Calls to `read_next_frame()` MUST be made to decode the audio data. // Calls to `decode_next_frame()` MUST be made to decode the audio data.
// This is the recommended way to read most FLAC files as it has a minimal memory overhead. // This is the recommended way to read most FLAC files as it has a minimal memory overhead.
load_from_file :: proc(filename: string, allocator := context.allocator) -> (flac: ^Flac, r: ^Reader, err: Error) { load_from_file :: proc(filename: string, allocator := context.allocator) -> (flac: ^Flac, r: ^Reader, err: Error) {
context.allocator = allocator context.allocator = allocator
file, open_err := os2.open(filename) file, open_err := os.open(filename)
if open_err != nil { if open_err != nil {
fmt.eprintln(open_err) fmt.eprintln(open_err)
return nil, {}, .Unable_To_Read_File return nil, nil, .Unable_To_Read_File
} }
br := new(bufio.Reader) br := new(bufio.Reader)
bufio.reader_init(br, os2.to_stream(file)) bufio.reader_init(br, os.to_stream(file))
r = new(Reader) reader := new(Reader)
r.r = bufio.reader_to_stream(br) reader.r = bufio.reader_to_stream(br)
r.buf = 0 reader.buf = 0
r.x = 0 reader.x = 0
r.n = 0 reader.n = 0
flac = read_metadata(r) or_return /* Without this an unreadable file in a scanned library burns an fd and the
reader's 4 KB buffer on every attempt -- the caller is handed nil for both
results and so has no handle to close the file with.
`reader` is a local for the same reason `read_metadata` keeps one: a defer
cannot nil out the named result, so `r` is only assigned on success.
*/
defer if err != nil {
bufio.reader_destroy(br)
free(br)
free(reader)
os.close(file)
}
return flac, r, nil flac = read_metadata(reader) or_return
return flac, reader, nil
} }
/* `destroy` cleans up and frees the memory allocated by all 3 loading functions. /* `destroy` cleans up and frees the memory allocated by all 3 loading functions.
The returned reader from `load_from_file` MUST be passed to `destroy` in order to close the file handle. The returned reader from `load_from_file` MUST be passed to `destroy` in order to close the file handle.
Both arguments may be nil, so it is safe to defer immediately after a load.
--- ---
The allocator that was used when loading the flac file MUST be passed to `destroy` in order to properly free The allocator that was used when loading the flac file MUST be passed to `destroy` in order to properly free
the memory, otherwise a bad free may occur and crash the program. the memory, otherwise a bad free may occur and crash the program.
@@ -903,21 +962,25 @@ load_from_file :: proc(filename: string, allocator := context.allocator) -> (fla
destroy :: proc(flac: ^Flac, r: ^Reader = nil, allocator := context.allocator) { destroy :: proc(flac: ^Flac, r: ^Reader = nil, allocator := context.allocator) {
context.allocator = allocator context.allocator = allocator
delete(flac.samples) // Tolerates a nil `flac` so a caller can `defer destroy(...)` straight after
for picture in flac.metadata.pictures { // a load without first checking whether the load succeeded.
delete(picture.mimetype) if flac != nil {
delete(picture.data) delete(flac.samples)
delete(picture.description) for picture in flac.metadata.pictures {
} delete(picture.mimetype)
delete(flac.metadata.pictures) delete(picture.data)
delete(picture.description)
}
delete(flac.metadata.pictures)
for comment in flac.metadata.vorbis_comments { for comment in flac.metadata.vorbis_comments {
delete(comment) delete(comment)
} }
delete(flac.metadata.vorbis_comments) delete(flac.metadata.vorbis_comments)
delete(flac.metadata.vendor_name) delete(flac.metadata.vendor_name)
free(flac) free(flac)
}
if r != nil { if r != nil {
br := cast(^bufio.Reader)r.data br := cast(^bufio.Reader)r.data
+4 -4
View File
@@ -212,10 +212,10 @@ CueSheet :: struct #packed {
media_catalog_num: [128]byte, media_catalog_num: [128]byte,
num_lead_in_samples: u64be, num_lead_in_samples: u64be,
using _: bit_field u8 { using _: bit_field u8 {
reserved: u8 | 7, reserved_1: u8 | 7,
compact_disc: bool | 1, compact_disc: bool | 1,
}, },
reserved: [258]byte, reserved_2: [258]byte,
num_tracks: u8, num_tracks: u8,
} }
@@ -225,11 +225,11 @@ CueSheetTrack :: struct #packed {
track_num: u8, track_num: u8,
ISRC: [12]byte, ISRC: [12]byte,
using _: bit_field u8 { using _: bit_field u8 {
reserved: u8 | 6, reserved_1: u8 | 6,
pre_emphasis: bool | 1, pre_emphasis: bool | 1,
track_type: TrackType | 1, track_type: TrackType | 1,
}, },
reserved: [13]byte, reserved_2: [13]byte,
num_track_index_points: u8, num_track_index_points: u8,
} }
+4 -1
View File
@@ -1,4 +1,3 @@
#+private
package flac package flac
import "core:io" import "core:io"
@@ -6,6 +5,8 @@ import "core:io"
/* Basic byte and bit reader. /* Basic byte and bit reader.
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.
*/ */
// Public because load_from_file hands one back; everything else in this file
// stays package-private.
Reader :: struct { Reader :: struct {
using r: io.Stream, using r: io.Stream,
// Temporary read buffer. // Temporary read buffer.
@@ -33,6 +34,7 @@ read_data :: #force_inline proc(r: ^Reader, $T: typeid) -> (res: T, err: io.Erro
// Read reads and returns the next n bits, at most 64. It buffers bits up to the // Read reads and returns the next n bits, at most 64. It buffers bits up to the
// next byte boundary. // next byte boundary.
// Borrowed from https://github.com/mewkiz/flac // Borrowed from https://github.com/mewkiz/flac
@(private)
read_bits :: proc(r: ^Reader, n: uint) -> (res: u64, err: io.Error) #no_bounds_check { read_bits :: proc(r: ^Reader, n: uint) -> (res: u64, err: io.Error) #no_bounds_check {
if n == 0 { if n == 0 {
return 0, nil return 0, nil
@@ -86,6 +88,7 @@ read_bits :: proc(r: ^Reader, n: uint) -> (res: u64, err: io.Error) #no_bounds_c
return res, nil return res, nil
} }
@(private)
align_to_byte :: proc(r: ^Reader) { align_to_byte :: proc(r: ^Reader) {
r.x = 0 r.x = 0
r.n = 0 r.n = 0
+90 -66
View File
@@ -3,6 +3,7 @@ package flac_test
import "core:fmt" import "core:fmt"
import "core:os" import "core:os"
import "core:testing" import "core:testing"
import "core:crypto/legacy/md5"
import "shared:flac" import "shared:flac"
@(test) @(test)
@@ -12,7 +13,7 @@ test_blocksize_4096 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Read Blocksize 4096 metadata Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Read Blocksize 4096 metadata Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -27,7 +28,7 @@ test_blocksize_4608 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Blocksize 4608 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Blocksize 4608 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -42,7 +43,7 @@ test_blocksize_16 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Blocksize 16 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Blocksize 16 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -57,7 +58,7 @@ test_blocksize_192 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Blocksize 192 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Blocksize 192 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -72,7 +73,7 @@ test_blocksize_254 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Blocksize 254 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Blocksize 254 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -87,7 +88,7 @@ test_blocksize_512 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Blocksize 512 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Blocksize 512 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -102,7 +103,7 @@ test_blocksize_725 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Blocksize 725 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Blocksize 725 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -117,7 +118,7 @@ test_blocksize_1000 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Blocksize 1000 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Blocksize 1000 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -132,7 +133,7 @@ test_blocksize_1937 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Blocksize 1937 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Blocksize 1937 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -147,7 +148,7 @@ test_blocksize_2304 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Blocksize 2304 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Blocksize 2304 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -162,7 +163,7 @@ test_partition_order_8 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Partition order 8 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Partition order 8 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -177,7 +178,7 @@ test_qlp_precision_15_bit :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("qlp precision 15 bit Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("qlp precision 15 bit Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -192,7 +193,7 @@ test_qlp_precision_2_bit :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("qlp precision 2 bit Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("qlp precision 2 bit Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -207,7 +208,7 @@ wasted_bits :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Wasted bits Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Wasted bits Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -222,7 +223,7 @@ only_verbatim_subframes :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Only verbatim subframes Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Only verbatim subframes Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -241,7 +242,7 @@ partition_order_8_containing_escaped_partitions :: proc(t: ^testing.T) {
) )
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -256,7 +257,7 @@ all_fixed_orders :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("All fixed orders Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("All fixed orders Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -271,7 +272,7 @@ precision_search :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Precision search Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Precision search Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -286,7 +287,7 @@ samplerate_35467Hz :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Samplerate 35467Hz Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Samplerate 35467Hz Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -301,7 +302,7 @@ samplerate_39kHz :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Samplerate 39kHz Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Samplerate 39kHz Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -316,7 +317,7 @@ samplerate_22050Hz :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Samplerate 22050Hz Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Samplerate 22050Hz Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -331,7 +332,7 @@ _12_bit_per_sample :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("12 bit per sample Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("12 bit per sample Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -346,7 +347,7 @@ _8_bit_per_sample :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("8 bit per sample Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("8 bit per sample Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -367,7 +368,7 @@ variable_blocksize_file_created_with_flake_revision_264 :: proc(t: ^testing.T) {
) )
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -391,7 +392,7 @@ variable_blocksize_file_created_with_flake_revision_264_modified_to_create_small
) )
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -412,7 +413,7 @@ variable_blocksize_file_created_with_CUETools_Flake_2_1_6 :: proc(t: ^testing.T)
) )
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -433,7 +434,7 @@ old_format_variable_blocksize_file_created_with_Flake_0_11 :: proc(t: ^testing.T
) )
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -448,7 +449,7 @@ high_resolution_audio_default_settings :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("High resolution audio, default settings Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("High resolution audio, default settings Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -463,7 +464,7 @@ high_resolution_audio_blocksize_16384 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("High resolution audio, blocksize 16384 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("High resolution audio, blocksize 16384 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -478,7 +479,7 @@ high_resolution_audio_blocksize_13456 :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("High resolution audio, blocksize 13456 Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("High resolution audio, blocksize 13456 Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -499,7 +500,7 @@ high_resolution_audio_using_only_32nd_order_predictors :: proc(t: ^testing.T) {
) )
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -520,7 +521,7 @@ high_resolution_audio_partition_order_8_containing_escaped_partitions :: proc(t:
) )
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -535,7 +536,7 @@ samplerate_192kHz :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Samplerate 192kHz Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Samplerate 192kHz Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -554,7 +555,7 @@ samplerate_192kHz_using_only_32nd_order_predictors :: proc(t: ^testing.T) {
) )
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -569,7 +570,7 @@ samplerate_134560Hz :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Samplerate 134560Hz Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Samplerate 134560Hz Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -584,7 +585,7 @@ samplerate_384kHz :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Samplerate 384kHz Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Samplerate 384kHz Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -599,7 +600,7 @@ _20_bit_per_sample :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("20 bit per sample Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("20 bit per sample Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -614,7 +615,7 @@ _3_channels :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("3 channels Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("3 channels Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -629,7 +630,7 @@ _4_channels :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("4 channels Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("4 channels Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -644,7 +645,7 @@ _5_channels :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("5 channels Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("5 channels Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -659,7 +660,7 @@ _6_channels :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("6 channels Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("6 channels Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -674,7 +675,7 @@ _7_channels :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("7 channels Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("7 channels Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -689,7 +690,7 @@ _8_channels :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("8 channels Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("8 channels Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -710,7 +711,7 @@ _8_channel_surround_192kHz_24_bit_using_only_32nd_order_predictors :: proc(t: ^t
) )
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -725,7 +726,7 @@ no_total_number_of_samples :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("No total number of samples Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("No total number of samples Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -740,7 +741,7 @@ no_min_max_framesize :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("No min-max framesize Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("No min-max framesize Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -755,7 +756,7 @@ only_streaminfo :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Only STREAMINFO Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Only STREAMINFO Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -770,7 +771,7 @@ extreme_large_seektable :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Extremely large SEEKTABLE Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Extremely large SEEKTABLE Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -785,7 +786,7 @@ extreme_large_padding :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Extremely large PADDING Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Extremely large PADDING Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -800,7 +801,7 @@ extreme_large_picture :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Extremely large PICTURE Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Extremely large PICTURE Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -815,7 +816,7 @@ extreme_large_vorbiscomment :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Extremely large VORBISCOMMENT Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Extremely large VORBISCOMMENT Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -830,7 +831,7 @@ extreme_large_application :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Extremely large APPLICATION Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Extremely large APPLICATION Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -845,7 +846,7 @@ cuesheet_with_very_many_indexes :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("CUESHEET with very many indexes Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("CUESHEET with very many indexes Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -860,7 +861,7 @@ _1000x_repeating_vorbiscomment :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("1000x repeating VORBSICOMMENT Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("1000x repeating VORBSICOMMENT Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -875,7 +876,7 @@ file_48_53_combined :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("File 48-53 combined Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("File 48-53 combined Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -890,7 +891,7 @@ jpg_picture :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("JPG PICTURE Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("JPG PICTURE Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -905,7 +906,7 @@ png_picture :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("PNG PICTURE Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("PNG PICTURE Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -920,7 +921,7 @@ gif_picture :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("GIF PICTURE Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("GIF PICTURE Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -935,7 +936,7 @@ avif_picture :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("AVIF PICTURE Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("AVIF PICTURE Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -950,7 +951,7 @@ mono_audio :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Mono audio Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Mono audio Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -965,7 +966,7 @@ predictor_overflow_check_16_bit :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Predictor overflow check, 16-bit Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Predictor overflow check, 16-bit Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -980,7 +981,7 @@ predictor_overflow_check_20_bit :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Predictor overflow check, 20-bit Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Predictor overflow check, 20-bit Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -995,7 +996,7 @@ predictor_overflow_check_24_bit :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Predictor overflow check, 24-bit Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Predictor overflow check, 24-bit Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -1010,7 +1011,7 @@ rice_partitions_with_escape_code_zero :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Rice partitions with escape code zero Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Rice partitions with escape code zero Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -1018,6 +1019,29 @@ rice_partitions_with_escape_code_zero :: proc(t: ^testing.T) {
} }
} }
@(test)
uncommon_changing_samplerate :: proc(t: ^testing.T) {
data, r, err := flac.load_from_file("flac-test-files/uncommon/01 - changing samplerate.flac")
defer flac.destroy(data, r)
testing.expect(t, err == nil, fmt.tprint("Uncommon changing samplerate Failed with error:", err))
md5_ctx: md5.Context
md5.init(&md5_ctx)
for {
frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF {
break
}
flac.md5hash(&md5_ctx, data.metadata.bits_per_sample, frame.samples)
testing.expect(t, f_err == nil, fmt.tprintf("Decoding Uncommon changing samplerate frame Failed with error:", f_err))
}
if data.metadata.expected_md5 != 0 {
testing.expect(t, flac.md5sum(&md5_ctx, data) == nil, fmt.tprintf("Incorrect MD5 hash. Expected %v. Got %v", data.metadata.expected_md5, data.metadata.calculated_md5))
}
}
@(test) @(test)
uncommon_32_bit_per_sample :: proc(t: ^testing.T) { uncommon_32_bit_per_sample :: proc(t: ^testing.T) {
data, r, err := flac.load_from_file("flac-test-files/uncommon/05 - 32bps audio.flac") data, r, err := flac.load_from_file("flac-test-files/uncommon/05 - 32bps audio.flac")
@@ -1025,7 +1049,7 @@ uncommon_32_bit_per_sample :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Uncommon 32bps audio Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Uncommon 32bps audio Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }
@@ -1040,7 +1064,7 @@ uncommon_samplerate_768kHz :: proc(t: ^testing.T) {
testing.expect(t, err == nil, fmt.tprint("Uncommon samplerate 768kHz Failed with error:", err)) testing.expect(t, err == nil, fmt.tprint("Uncommon samplerate 768kHz Failed with error:", err))
for { for {
frame, f_err := flac.read_next_frame(r, data) frame, f_err := flac.decode_next_frame(r, data)
if f_err == .EOF { if f_err == .EOF {
break break
} }