summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wav.c72
-rw-r--r--src/wav.h9
2 files changed, 62 insertions, 19 deletions
diff --git a/src/wav.c b/src/wav.c
index 61765d6..665998d 100644
--- a/src/wav.c
+++ b/src/wav.c
@@ -5,48 +5,90 @@
#include <stdio.h>
#include <string.h>
-void seek_to_chunk(FILE *file, char *chunk_name) {
+b32 seek_to_chunk(FILE *file, char const *chunk_name) {
char cur_name[4];
u32 chunk_size;
+ fseek(file, 0, SEEK_END);
+ const i64 max_pos = ftell(file);
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;
- }
+ if (memcmp(cur_name, chunk_name, 4) == 0) break;
+
+ if (chunk_size % 2 == 1) chunk_size++;
+
+ if (ftell(file) + (i64)chunk_size >= max_pos) return false;
fseek(file, chunk_size, SEEK_CUR);
}
fseek(file, -8, SEEK_CUR);
+ return true;
}
-wav_data_t *load_wav_file(smrt_arena_t *arena, char *filename, wav_master_chunk_t *master_o, wav_fmt_chunk_t *format_o) {
+wav_data_t load_wav_file(smrt_arena_t *arena, char *filename, wav_master_chunk_t *master_o, wav_fmt_chunk_t *format_o) {
+ wav_data_t data = { 0 };
+
FILE *wav_file = fopen(filename, "rb");
- if (!wav_file) {
- return NULL;
- }
+ if (!wav_file) return data;
fread(master_o, sizeof(wav_master_chunk_t), 1, wav_file);
- seek_to_chunk(wav_file, "fmt ");
+ if (seek_to_chunk(wav_file, "fmt ") == false) return data;
fread(format_o, sizeof(wav_fmt_chunk_t), 1, wav_file);
- seek_to_chunk(wav_file, "data");
+ if (seek_to_chunk(wav_file, "data") == false) return 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);
+ data.samples = smrt_arena_push(arena, sizeof(wav_data_t) + sampled_data_size, true);
+ if (!data.samples) return data;
+
+ fread((u8*)data.samples+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);
+b32 write_wav_file(char *filename, wav_fmt_chunk_t *fmt_chunk_i, wav_data_t data_i) {
+ FILE *wav_file = fopen(filename, "wb");
+
+ if (!wav_file) return false;
+
+ u64 data_size_bytes = data_i.sample_count * fmt_chunk_i->bytes_per_block;
+
+ wav_master_chunk_t mchunk = {
+ .file_size = sizeof(wav_master_chunk_t) + sizeof(wav_fmt_chunk_t) + sizeof(wav_data_t) + data_size_bytes
+ };
+
+ memcpy(&mchunk.chunk_id, "RIFF", 4);
+ memcpy(&mchunk.file_format_id, "WAVE", 4);
+
+ fwrite(&mchunk, sizeof(wav_master_chunk_t), 1, wav_file);
+ fwrite(fmt_chunk_i, sizeof(wav_data_t), 1, wav_file);
+ fwrite(data_i.samples, sizeof(u8), data_size_bytes, wav_file);
+
+ return true;
+}
+
+wav_fmt_chunk_t make_wav_fmt_chunk(u32 num_channels, u32 sample_rate, u16 bits_per_sample, wav_data_t data_i) {
+ u64 data_size_bytes = data_i.sample_count * (num_channels * (bits_per_sample / 8));
+ wav_fmt_chunk_t o = {
+ .chunk_size = sizeof(wav_fmt_chunk_t) + data_size_bytes - 8,
+ .bits_per_sample = bits_per_sample,
+ .num_channels = num_channels,
+ .sample_rate = sample_rate,
+ .bytes_per_block = num_channels * (bits_per_sample / 8),
+ .audio_format = 1,
+ };
+ o.bytes_per_sec = o.bytes_per_block * sample_rate;
+ memcpy(&o.chunk_id, "data", 4);
+
+ return o;
+}
diff --git a/src/wav.h b/src/wav.h
index dd85ccd..773cc2a 100644
--- a/src/wav.h
+++ b/src/wav.h
@@ -7,6 +7,7 @@
typedef struct {
u64 sample_count;
+ u8 *samples;
} wav_data_t;
// [Master RIFF chunk]
@@ -35,12 +36,12 @@ typedef struct {
u16 audio_format;
u16 num_channels;
u32 sample_rate;
- u32 byter_per_sec;
+ u32 bytes_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);
+ wav_data_t load_wav_file(smrt_arena_t *arena, char *filename, wav_master_chunk_t *master_o, wav_fmt_chunk_t *format_o);
+ b32 write_wav_file(char *filename, wav_fmt_chunk_t *fmt_chunk_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);