aboutsummaryrefslogtreecommitdiff
path: root/src/wav/wav.odin
diff options
context:
space:
mode:
authorSan Jacobs2025-11-12 05:21:32 +0100
committerSan Jacobs2025-11-12 05:21:32 +0100
commit09ec5f18a0583c94286f1f1f1b462f675d93d94d (patch)
treed7162f3576e5e4fb93edd61f1bdf7f73235b3703 /src/wav/wav.odin
parent5929af19af3d74eececa97cc1bf305102614492b (diff)
downloadbetter-report-master.tar.gz
better-report-master.tar.bz2
better-report-master.zip
Starting to read wav metadata directlyHEADmaster
Diffstat (limited to 'src/wav/wav.odin')
-rw-r--r--src/wav/wav.odin140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/wav/wav.odin b/src/wav/wav.odin
new file mode 100644
index 0000000..04cb0cf
--- /dev/null
+++ b/src/wav/wav.odin
@@ -0,0 +1,140 @@
+package wav
+
+import "core:fmt"
+import "core:math"
+import "core:strings"
+import "core:os"
+
+Wav :: struct {
+ path : string,
+ handle : os.Handle,
+ buf : []u8,
+ reported_size : u32,
+ bext : string,
+ ixml : string,
+ format : Audio_Format,
+ channels : int,
+ channel_names : []string,
+ sample_rate : int,
+ bit_depth : int,
+}
+Audio_Format :: enum {
+ PCM = 1,
+ FLOAT = 3,
+}
+
+BUFFER_SIZE :: 1<<15
+
+main :: proc() {
+ sweden, sweden_ok := read_wav("test/sweden.wav", context.temp_allocator)
+ fmt.printf("\n\nsweden = %#v\n\n", sweden)
+ enok, enok_ok := read_wav("test/ENOKS-BIRHTDAYT02.WAV", context.temp_allocator)
+ fmt.printf("\n\nenok = %#v\n\n", enok)
+}
+
+
+read_wav :: proc(path : string, allocator:=context.allocator) -> (Wav, bool) {
+ file : Wav
+
+ file_ok : os.Error
+ file.handle, file_ok = os.open(path)
+ defer os.close(file.handle)
+ assert(file_ok == os.General_Error.None)
+
+ file.buf = new([BUFFER_SIZE]u8)[:]
+ defer delete(file.buf)
+
+ os.read(file.handle, file.buf)
+
+
+ head : int = 0
+
+ // RIFF header
+ fmt.println(string(file.buf[0:4]))
+ if string(file.buf[0:4]) != "RIFF" do return {}, false
+ head += 4
+
+ // Size
+ file.reported_size = read_little_endian_u32(file.buf[head:head+4])
+ fmt.println("Reported size:", file.reported_size)
+ head += 4
+
+ // Confirming again that this is a wave file
+ fmt.println(string(file.buf[head:head+4]))
+ if string(file.buf[head:head+4]) != "WAVE" do return {}, false
+ head += 4
+
+ fmt.println("\nChunks:\n")
+
+ // Looping through chunks
+ for _ in 0..<BUFFER_SIZE {
+ chunk_id := string(file.buf[head:head+4])
+ head += 4
+ chunk_size := int(read_little_endian_u32(file.buf[head:head+4]))
+ head += 4
+ fmt.println(chunk_id,"\n-------------------------------------")
+
+ if head+chunk_size < BUFFER_SIZE {
+ print_data : string
+ data_end := head+chunk_size
+ read_end := min(head+15000, data_end)
+ switch chunk_id {
+ case "iXML":
+ print_data = string(file.buf[head:read_end])
+ file.ixml = strings.clone(string(file.buf[head:data_end]), allocator=allocator)
+ case "bext":
+ print_data = string(file.buf[head:read_end])
+ file.bext = strings.clone(string(file.buf[head:data_end]), allocator=allocator)
+ case "fmt ":
+ file.format = Audio_Format(read_little_endian_u16(file.buf[head:]))
+ head += 2
+ file.channels = int(read_little_endian_u16(file.buf[head:]))
+ head += 2
+ file.sample_rate = int(read_little_endian_u32(file.buf[head:]))
+ head += 4
+
+ // Skipping byte rate and block align.
+ // These two legacy fields are only ever redundant or wrong,
+ // and are implied by the other fields.
+ head += 4 + 2
+
+ file.bit_depth = int(read_little_endian_u16(file.buf[head:]))
+ head += 2
+ }
+ fmt.println(print_data, "\n")
+ } else {
+ break
+ }
+
+
+ head += chunk_size
+ }
+
+ file.channel_names = make([]string, file.channels)
+
+ naming_channel := 0
+ for line in strings.split_lines(file.bext) {
+ if strings.starts_with(line, "sTRK") {
+ eq_index := strings.index(line, "=")
+ file.channel_names[naming_channel] = strings.clone(line[eq_index+1:], allocator=allocator)
+ naming_channel += 1
+ }
+ }
+
+ delete(file.buf)
+ file.buf = nil
+ return file, true
+}
+
+
+read_little_endian_u32 :: proc(x : []u8) -> u32 {
+ return u32(x[0]) |
+ u32(x[1]) << 8 |
+ u32(x[2]) << 16 |
+ u32(x[3]) << 24
+}
+
+read_little_endian_u16 :: proc(x : []u8) -> u16 {
+ return u16(x[0]) |
+ u16(x[1]) << 8
+} \ No newline at end of file