summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wav.c52
-rw-r--r--src/wav.h46
-rw-r--r--tests/fixtures/sine.wavbin0 -> 96044 bytes
-rw-r--r--tests/smrt_arena.c2
-rw-r--r--tests/string.c3
-rw-r--r--tests/wav.c27
6 files changed, 127 insertions, 3 deletions
diff --git a/src/wav.c b/src/wav.c
new file mode 100644
index 0000000..61765d6
--- /dev/null
+++ b/src/wav.c
@@ -0,0 +1,52 @@
+#include "wav.h"
+#include "smrt_arena.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+void seek_to_chunk(FILE *file, char *chunk_name) {
+ char cur_name[4];
+ u32 chunk_size;
+
+ fseek(file, sizeof(wav_master_chunk_t), SEEK_SET);
+ while (true) {
+ fread(cur_name, 4, 1, file);
+ fread(&chunk_size, 4, 1, file);
+
+ if (strcmp(cur_name, chunk_name) == 0) {
+ break;
+ }
+
+ fseek(file, chunk_size, SEEK_CUR);
+ }
+
+ fseek(file, -8, SEEK_CUR);
+}
+
+wav_data_t *load_wav_file(smrt_arena_t *arena, char *filename, wav_master_chunk_t *master_o, wav_fmt_chunk_t *format_o) {
+ FILE *wav_file = fopen(filename, "rb");
+
+ if (!wav_file) {
+ return NULL;
+ }
+
+ fread(master_o, sizeof(wav_master_chunk_t), 1, wav_file);
+
+ seek_to_chunk(wav_file, "fmt ");
+ fread(format_o, sizeof(wav_fmt_chunk_t), 1, wav_file);
+
+ seek_to_chunk(wav_file, "data");
+ fseek(wav_file, 4, SEEK_CUR);
+ u32 sampled_data_size;
+ fread(&sampled_data_size, 4, 1, wav_file);
+
+ wav_data_t *data = smrt_arena_push(arena, sizeof(wav_data_t) + sampled_data_size, true);
+ fread((u8*)data+WAV_DATA_BASE_POS, sampled_data_size, 1, wav_file);
+ data->sample_count = sampled_data_size / ((format_o->bits_per_sample / 8) * format_o->num_channels);
+
+ return data;
+}
+
+void write_wav_file(char *filename, wav_fmt_chunk_t *header_i, wav_data_t *data_i);
+wav_fmt_chunk_t make_wav_fmt_chunk(u32 num_channels, u32 sample_rate, u16 bits_per_sample, wav_data_t *data_i);
diff --git a/src/wav.h b/src/wav.h
new file mode 100644
index 0000000..dd85ccd
--- /dev/null
+++ b/src/wav.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "common.h"
+#include "smrt_arena.h"
+
+#define WAV_DATA_BASE_POS sizeof(wav_data_t)
+
+typedef struct {
+ u64 sample_count;
+} wav_data_t;
+
+// [Master RIFF chunk]
+// FileTypeBlocID (4 bytes) : Identifier « RIFF » (0x52, 0x49, 0x46, 0x46)
+// FileSize (4 bytes) : Overall file size minus 8 bytes
+// FileFormatID (4 bytes) : Format = « WAVE » (0x57, 0x41, 0x56, 0x45)
+#pragma pack(push, 1)
+typedef struct {
+ u8 chunk_id[4];
+ u32 file_size;
+ u8 file_format_id[4];
+} wav_master_chunk_t;
+
+// [Chunk describing the data format]
+// FormatBlocID (4 bytes) : Identifier « fmt␣ » (0x66, 0x6D, 0x74, 0x20)
+// BlocSize (4 bytes) : Chunk size minus 8 bytes
+// AudioFormat (2 bytes) : Audio format (1: PCM integer, 3: IEEE 754 float)
+// NbrChannels (2 bytes) : Number of channels
+// Frequency (4 bytes) : Sample rate (in hertz)
+// BytePerSec (4 bytes) : Number of bytes to read per second (Frequency * BytePerBloc).
+// BytePerBloc (2 bytes) : Number of bytes per block (NbrChannels * BitsPerSample / 8).
+// BitsPerSample (2 bytes) : Number of bits per sample
+typedef struct {
+ u8 chunk_id[4];
+ u32 chunk_size;
+ u16 audio_format;
+ u16 num_channels;
+ u32 sample_rate;
+ u32 byter_per_sec;
+ u16 bytes_per_block;
+ u16 bits_per_sample;
+} wav_fmt_chunk_t;
+#pragma pack(pop)
+
+ wav_data_t *load_wav_file(smrt_arena_t *arena, char *filename, wav_master_chunk_t *master_o, wav_fmt_chunk_t *format_o);
+ void write_wav_file(char *filename, wav_fmt_chunk_t *header_i, wav_data_t *data_i);
+wav_fmt_chunk_t make_wav_fmt_chunk(u32 num_channels, u32 sample_rate, u16 bits_per_sample, wav_data_t *data_i);
diff --git a/tests/fixtures/sine.wav b/tests/fixtures/sine.wav
new file mode 100644
index 0000000..8e01d11
--- /dev/null
+++ b/tests/fixtures/sine.wav
Binary files differ
diff --git a/tests/smrt_arena.c b/tests/smrt_arena.c
index 5e3ef5c..505a5e0 100644
--- a/tests/smrt_arena.c
+++ b/tests/smrt_arena.c
@@ -9,7 +9,7 @@
#include <criterion/internal/test.h>
Test(smrt_arena, create_arena) {
- smrt_arena_t *arena = smrt_arena_create(KiB(1), KiB(4), false);
+ smrt_arena_t *arena = smrt_arena_create(KiB(1), plat_get_pagesize(), false);
cr_expect(arena->reserve_size == MAX(KiB(1), plat_get_pagesize()));
cr_expect(arena->pos == SMRT_ARENA_BASE_POS);
diff --git a/tests/string.c b/tests/string.c
index 38109a7..794bcfb 100644
--- a/tests/string.c
+++ b/tests/string.c
@@ -2,11 +2,11 @@
#include <stddef.h>
#include <stdio.h>
+#include <string.h>
#include <criterion/criterion.h>
#include <criterion/internal/assert.h>
#include <criterion/internal/test.h>
-#include <string.h>
Test(string, create_string) {
smrt_arena_t *arena = smrt_arena_create(KiB(4), KiB(4), false);
@@ -64,7 +64,6 @@ Test(string, string_duplicate) {
strng_t *dup = strng_dup(arena, orig);
- printf("%.*s\n", STRNG_FMT(dup));
cr_expect(dup->alloc_size == 26);
cr_expect(dup->len == 26);
diff --git a/tests/wav.c b/tests/wav.c
new file mode 100644
index 0000000..aac7f9d
--- /dev/null
+++ b/tests/wav.c
@@ -0,0 +1,27 @@
+#include "../src/wav.h"
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <criterion/criterion.h>
+#include <criterion/internal/assert.h>
+#include <criterion/internal/test.h>
+#include <string.h>
+
+Test(wav, read_file) {
+ smrt_arena_t *arena = smrt_arena_create(MiB(4), KiB(4), false);
+
+ wav_master_chunk_t mchunk;
+ wav_fmt_chunk_t fmtchunk;
+
+ wav_data_t *data = load_wav_file(arena, "./tests/fixtures/sine.wav", &mchunk, &fmtchunk);
+
+ u8 idcheck[4] = { 'f', 'm', 't', ' ' };
+ cr_expect(memcmp(fmtchunk.chunk_id, idcheck, 4) == 0);
+ cr_expect(fmtchunk.audio_format == 1);
+ cr_expect(fmtchunk.num_channels == 1);
+ cr_expect(fmtchunk.bits_per_sample == 16);
+ cr_expect(data->sample_count == 48000);
+
+ smrt_arena_destroy(arena);
+}