Login
1 branch 0 tags
Ben (Desktop/Arch) Added screen transitions 37e8c6e 1 month ago 71 Commits
moon / src / metadata / wav.c
#include "../audio_metadata.h"
#include "helper.h"

#include <stdio.h>
#include <string.h>

bool parse_wav(const char* path, audio_metadata_t* meta) {
	FILE* f = fopen(path, "rb");
	if (!f) {
		return false;
	}

	// Read RIFF header (12 bytes)
	uint8_t header[12];
	if (fread(header, 1, 12, f) != 12) {
		fclose(f);
		return false;
	}

	// Verify "RIFF" and "WAVE"
	if (memcmp(header, "RIFF", 4) != 0 || memcmp(header + 8, "WAVE", 4) != 0) {
		fclose(f);
		return false;
	}

	uint32_t byte_rate = 0;
	uint32_t data_size = 0;
	bool got_fmt = false;
	bool got_data = false;

	// Parse sub-chunks
	while (!got_fmt || !got_data) {
		uint8_t chunk_header[8];
		if (fread(chunk_header, 1, 8, f) != 8) {
			break;
		}

		char chunk_id[5] = {chunk_header[0], chunk_header[1], chunk_header[2],
		                    chunk_header[3], 0};
		uint32_t chunk_size = (uint32_t)chunk_header[4] |
		                      ((uint32_t)chunk_header[5] << 8) |
		                      ((uint32_t)chunk_header[6] << 16) |
		                      ((uint32_t)chunk_header[7] << 24);

		if (strcmp(chunk_id, "fmt ") == 0) {
			if (chunk_size < 16) {
				break;
			}
			uint8_t fmt[16];
			if (fread(fmt, 1, 16, f) != 16) {
				break;
			}

			meta->channels = (uint8_t)(fmt[2] | (fmt[3] << 8));
			meta->sample_rate = (uint32_t)fmt[4] | ((uint32_t)fmt[5] << 8) |
			                    ((uint32_t)fmt[6] << 16) |
			                    ((uint32_t)fmt[7] << 24);
			byte_rate = (uint32_t)fmt[8] | ((uint32_t)fmt[9] << 8) |
			            ((uint32_t)fmt[10] << 16) | ((uint32_t)fmt[11] << 24);

			// Skip remaining fmt data
			if (chunk_size > 16) {
				fseek(f, chunk_size - 16, SEEK_CUR);
			}
			got_fmt = true;
		} else if (strcmp(chunk_id, "data") == 0) {
			data_size = chunk_size;
			got_data = true;
			// Don't need to read data, just skip
			fseek(f, chunk_size, SEEK_CUR);
		} else {
			// Skip unknown chunk
			fseek(f, chunk_size, SEEK_CUR);
		}
	}

	fclose(f);

	if (!got_fmt || !got_data || byte_rate == 0) {
		return false;
	}

	meta->bitrate = byte_rate * 8;
	meta->duration_ms = (uint32_t)((uint64_t)data_size * 1000 / byte_rate);
	meta->valid = true;
	return true;
}