aboutsummaryrefslogtreecommitdiff
path: root/src/wav
diff options
context:
space:
mode:
Diffstat (limited to 'src/wav')
-rw-r--r--src/wav/wav.odin250
1 files changed, 127 insertions, 123 deletions
diff --git a/src/wav/wav.odin b/src/wav/wav.odin
index f2cf85c..01fbad1 100644
--- a/src/wav/wav.odin
+++ b/src/wav/wav.odin
@@ -18,10 +18,7 @@ Wav :: struct {
reported_size : u32,
// Metadata
- buf : []u8,
channel_names : []string,
- bext : []u8,
- ixml : string,
samples_since_midnight: u64,
timecode : Timecode,
tc_framerate : f32,
@@ -56,38 +53,44 @@ main :: proc() {
fmt.printf("\n\nf8 = %#v\n\n", f8)
}
-// TODO: Maybe split reading metadata into its own function call.
-
+/*
+Reads in the wav file data, including metadata.
+*/
read_wav :: proc(path : string, allocator:=context.allocator) -> (Wav, bool) {
file : Wav
- file_ok : os.Error
- file.handle, file_ok = os.open(path)
+ load_err : os.Error
+ file.handle, load_err = os.open(path)
defer os.close(file.handle)
defer file.handle = 0
- assert(file_ok == os.General_Error.None)
+ if load_err != os.General_Error.None {
+ fmt.eprintln("ERROR %v: Unable to load file \"%v\"", load_err, path)
+ return {}, false
+ }
- file.buf = new([BUFFER_SIZE]u8)[:]
- defer delete(file.buf)
- os.read(file.handle, file.buf)
+ temp_buf := new([BUFFER_SIZE]u8)[:]
+ temp_bext : []u8
+ temp_ixml : string
+ defer delete(temp_buf)
+ os.read(file.handle, temp_buf)
head : int = 0
// RIFF header
- fmt.println(string(file.buf[0:4]))
- if string(file.buf[0:4]) != "RIFF" do return {}, false
+ fmt.println(string(temp_buf[0:4]))
+ if string(temp_buf[0:4]) != "RIFF" do return {}, false
head += 4
// Size
- file.reported_size = read_little_endian_u32(file.buf[head:head+4])
+ file.reported_size = read_little_endian_u32(temp_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
+
+ // Confirming again that this is a wave file
+ fmt.println(string(temp_buf[head:head+4]))
+ if string(temp_buf[head:head+4]) != "WAVE" do return {}, false
head += 4
fmt.println("\nChunks:\n")
@@ -95,10 +98,10 @@ read_wav :: proc(path : string, allocator:=context.allocator) -> (Wav, bool) {
// Looping through chunks
null_chunks := 0
for _ in 0..<BUFFER_SIZE {
- chunk_id_raw := file.buf[head:head+4]
+ chunk_id_raw := temp_buf[head:head+4]
chunk_id := string(chunk_id_raw)
head += 4
- chunk_size := int(read_little_endian_u32(file.buf[head:head+4]))
+ chunk_size := int(read_little_endian_u32(temp_buf[head:head+4]))
head += 4
fmt.println(chunk_id, chunk_size,"\n-------------------------------------")
data_reached := false
@@ -110,21 +113,21 @@ read_wav :: proc(path : string, allocator:=context.allocator) -> (Wav, bool) {
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)
+ temp_ixml = string(temp_buf[head:data_end])
+ //print_data = temp_ixml
null_chunks = 0
case "bext":
- print_data = string(file.buf[head:read_end])
- file.bext = file.buf[head:data_end]
+ temp_bext = temp_buf[head:data_end]
+ //print_data = string(temp_bext)
null_chunks = 0
case "fmt ":
- file.format = Audio_Format(read_little_endian_u16(file.buf[head:]))
+ file.format = Audio_Format(read_little_endian_u16(temp_buf[head:]))
fmt.println("Format:", file.format)
head += 2
- file.channels = int(read_little_endian_u16(file.buf[head:]))
+ file.channels = int(read_little_endian_u16(temp_buf[head:]))
fmt.println("Channels:", file.channels)
head += 2
- file.sample_rate = int(read_little_endian_u32(file.buf[head:]))
+ file.sample_rate = int(read_little_endian_u32(temp_buf[head:]))
fmt.println("Sample rate:", file.sample_rate)
head += 4
@@ -133,7 +136,7 @@ read_wav :: proc(path : string, allocator:=context.allocator) -> (Wav, bool) {
// and are implied by the other fields.
head += 4 + 2
- file.bit_depth = int(read_little_endian_u16(file.buf[head:]))
+ file.bit_depth = int(read_little_endian_u16(temp_buf[head:]))
fmt.println("Bit depth:", file.bit_depth)
head += 2
head = data_end
@@ -167,104 +170,15 @@ read_wav :: proc(path : string, allocator:=context.allocator) -> (Wav, bool) {
- // bext parsing
- if len(file.bext) > 0 {
-
- // Stripping null padding
- end := len(file.bext) - 1
- for end >= 0 && file.bext[end] == 0 {
- end -= 1
- }
- file.bext = file.bext[:end]
-
- naming_channel := 0
-
- description := string(file.bext[:256])
- for line in strings.split_lines(description) {
- if strings.starts_with(line, "sTRK") || strings.starts_with(line, "zTRK") {
- eq_index := strings.index(line, "=")
- file.channel_names[naming_channel] = strings.clone(line[eq_index+1:], allocator=allocator)
- naming_channel += 1
- }
- if strings.starts_with(line[1:], "TAKE=") {
- file.take, _ = strconv.parse_int(line[6:])
- }
- if strings.starts_with(line[1:], "CIRCLED=") {
- file.circled = line[9:] == "TRUE"
- }
- if strings.starts_with(line[1:], "SPEED=") {
- value := line[7:]
- num_end : int
- type_start : int
- for r, i in value {
- if !strings.contains_rune("1234567890.", r) && num_end == 0 {
- num_end = i
- }
- if r=='N' || r=='D' {
- type_start = i
- break
- }
- }
- file.tc_framerate, _ = strconv.parse_f32(value[:num_end])
- file.tc_dropframe = value[type_start:] != "ND"
-
- }
- // Only if ixml doesn't exist, so we don't allocate the note string twice.
- if file.ixml == "" {
- if strings.starts_with(line[1:], "NOTE=") {
- v := line[6:]
- if v != "" {
- file.note = strings.clone(v, allocator=allocator)
- }
- }
- }
- }
- head := 0
- fmt.printf("Description: \n%v\n", string(file.bext[head:256]))
- head += 256
- fmt.printf("Originator: %v\n", string(file.bext[head:head+32]))
- head += 32
- fmt.printf("Originator Reference: %v\n", string(file.bext[head:head+32]))
- head += 32
- fmt.printf("Origination Date: %v\n", string(file.bext[head:head+10]))
- head += 10
- fmt.printf("Origination Time: %v\n", string(file.bext[head:head+8]))
- head += 8
-
- file.samples_since_midnight = read_little_endian_u64(file.bext[head:head+8])
-
- seconds_since_midnight := file.samples_since_midnight / u64(file.sample_rate)
- file.timecode.hour = u8( seconds_since_midnight / 3600)
- file.timecode.minute = u8((seconds_since_midnight % 3600) / 60)
- file.timecode.second = u8( seconds_since_midnight % 60)
- file.timecode.frame = f32( f64(file.samples_since_midnight % u64(file.sample_rate) ) * f64(file.tc_framerate) / f64(file.sample_rate))
- fmt.printf("Time Reference: %v (Samples since midnight, source of timecode)\n", file.samples_since_midnight)
- fmt.printf(" %v seconds + %v samples\n", seconds_since_midnight, file.samples_since_midnight % u64(file.sample_rate))
- head += 8
-
- fmt.printf("Version: %v\n", read_little_endian_u16(file.bext[head:head+2]))
- head += 2
- fmt.printf("UMID Skipped.\n")
- head += 64
- fmt.printf("Skipped reserved nothingness.\n")
- head += 190
- fmt.printf("Coding history:\n%v\n", string(file.bext[head:]))
- }
- fmt.println()
-
- // just here to make some printing prettier
- file.bext = nil
-
-
// iXML Parsing
- if file.ixml != "" {
+ if temp_ixml != "" {
// Stripping null padding
- end := len(file.ixml) - 1
- for end >= 0 && file.ixml[end] == 0 {
+ end := len(temp_ixml) - 1
+ for end >= 0 && temp_ixml[end] == 0 {
end -= 1
}
- file.ixml = file.ixml[:end]
+ temp_ixml = temp_ixml[:end]
naming_channel := 0
@@ -406,14 +320,104 @@ read_wav :: proc(path : string, allocator:=context.allocator) -> (Wav, bool) {
parsed_ixml : ^xml.Document
- parsed_ixml, _ = xml.parse(file.ixml, xml.Options{
+ parsed_ixml, _ = xml.parse(temp_ixml, xml.Options{
flags={.Ignore_Unsupported},
expected_doctype = "",
})
xml_recurse(parsed_ixml, 0, &file, &naming_channel, &interleave_set, allocator)
}
- file.buf = nil
+ // bext parsing
+ if len(temp_bext) > 0 {
+
+ // Stripping null padding
+ end := len(temp_bext) - 1
+ for end >= 0 && temp_bext[end] == 0 {
+ end -= 1
+ }
+ temp_bext = temp_bext[:end]
+
+ naming_channel := 0
+
+ description := string(temp_bext[:256])
+ for line in strings.split_lines(description) {
+
+ if file.channel_names[naming_channel] == "" &&
+ (strings.starts_with(line, "sTRK") || strings.starts_with(line, "zTRK")) {
+ eq_index := strings.index(line, "=")
+ file.channel_names[naming_channel] = strings.clone(line[eq_index+1:], allocator=allocator)
+ naming_channel += 1
+ }
+ if strings.starts_with(line[1:], "TAKE=") {
+ file.take, _ = strconv.parse_int(line[6:])
+ }
+ if strings.starts_with(line[1:], "CIRCLED=") {
+ file.circled = line[9:] == "TRUE"
+ }
+ if strings.starts_with(line[1:], "SPEED=") {
+ value := line[7:]
+ num_end : int
+ type_start : int
+ for r, i in value {
+ if !strings.contains_rune("1234567890.", r) && num_end == 0 {
+ num_end = i
+ }
+ if r=='N' || r=='D' {
+ type_start = i
+ break
+ }
+ }
+ file.tc_framerate, _ = strconv.parse_f32(value[:num_end])
+ file.tc_dropframe = value[type_start:] != "ND"
+
+ }
+ // Only if ixml doesn't exist, so we don't allocate the note string twice.
+ if file.note == "" {
+ if strings.starts_with(line[1:], "NOTE=") {
+ v := line[6:]
+ if v != "" {
+ file.note = strings.clone(v, allocator=allocator)
+ }
+ }
+ }
+ }
+ head := 0
+ fmt.printf("Description: \n%v\n", string(temp_bext[head:256]))
+ head += 256
+ fmt.printf("Originator: %v\n", string(temp_bext[head:head+32]))
+ head += 32
+ fmt.printf("Originator Reference: %v\n", string(temp_bext[head:head+32]))
+ head += 32
+ fmt.printf("Origination Date: %v\n", string(temp_bext[head:head+10]))
+ head += 10
+ fmt.printf("Origination Time: %v\n", string(temp_bext[head:head+8]))
+ head += 8
+
+ file.samples_since_midnight = read_little_endian_u64(temp_bext[head:head+8])
+
+ seconds_since_midnight := file.samples_since_midnight / u64(file.sample_rate)
+ file.timecode.hour = u8( seconds_since_midnight / 3600)
+ file.timecode.minute = u8((seconds_since_midnight % 3600) / 60)
+ file.timecode.second = u8( seconds_since_midnight % 60)
+ file.timecode.frame = f32( f64(file.samples_since_midnight % u64(file.sample_rate) ) * f64(file.tc_framerate) / f64(file.sample_rate))
+ fmt.printf("Time Reference: %v (Samples since midnight, source of timecode)\n", file.samples_since_midnight)
+ fmt.printf(" %v seconds + %v samples\n", seconds_since_midnight, file.samples_since_midnight % u64(file.sample_rate))
+ head += 8
+
+ fmt.printf("Version: %v\n", read_little_endian_u16(temp_bext[head:head+2]))
+ head += 2
+ fmt.printf("UMID Skipped.\n")
+ head += 64
+ fmt.printf("Skipped reserved nothingness.\n")
+ head += 190
+ fmt.printf("Coding history:\n%v\n", string(temp_bext[head:]))
+ }
+ fmt.println()
+
+ // just here to make some printing prettier
+ temp_bext = nil
+
+ temp_buf = nil
return file, true
}