Last active
June 15, 2024 20:46
-
-
Save SteelPh0enix/e44d4a030dd8816309af84809ed75604 to your computer and use it in GitHub Desktop.
Simple parser for WAV files, written in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "wave.h" | |
#include <stdio.h> | |
#include <string.h> | |
// Convert 32-bit unsigned little-endian value to big-endian from byte array | |
static inline uint32_t little2big_u32(uint8_t const* data) { | |
return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | |
} | |
// Convert 16-bit unsigned little-endian value to big-endian from byte array | |
static inline uint16_t little2big_u16(uint8_t const* data) { | |
return data[0] | (data[1] << 8); | |
} | |
// Copy n bytes from source to destination and terminate the destination with | |
// null character. Destination must be at least (amount + 1) bytes big to | |
// account for null character. | |
static inline void bytes_to_string(uint8_t const* source, | |
char* destination, | |
size_t amount) { | |
memcpy(destination, source, amount); | |
destination[amount] = '\0'; | |
} | |
// Parse the header of WAV file and return WAVFile structure with header and | |
// pointer to data | |
WAVFile WAV_ParseFileData(uint8_t const* data) { | |
WAVFile file; | |
uint8_t const* data_ptr = data; | |
bytes_to_string(data_ptr, file.header.file_id, 4); | |
data_ptr += 4; | |
file.header.file_size = little2big_u32(data_ptr); | |
data_ptr += 4; | |
bytes_to_string(data_ptr, file.header.format, 4); | |
data_ptr += 4; | |
bytes_to_string(data_ptr, file.header.subchunk_id, 4); | |
data_ptr += 4; | |
file.header.subchunk_size = little2big_u32(data_ptr); | |
data_ptr += 4; | |
file.header.audio_format = little2big_u16(data_ptr); | |
data_ptr += 2; | |
file.header.number_of_channels = little2big_u16(data_ptr); | |
data_ptr += 2; | |
file.header.sample_rate = little2big_u32(data_ptr); | |
data_ptr += 4; | |
file.header.byte_rate = little2big_u32(data_ptr); | |
data_ptr += 4; | |
file.header.block_align = little2big_u16(data_ptr); | |
data_ptr += 2; | |
file.header.bits_per_sample = little2big_u16(data_ptr); | |
data_ptr += 2; | |
bytes_to_string(data_ptr, file.header.data_id, 4); | |
data_ptr += 4; | |
file.header.data_size = little2big_u32(data_ptr); | |
data_ptr += 4; | |
file.data = data_ptr; | |
file.data_length = file.header.data_size; | |
return file; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef WAVE_H | |
#define WAVE_H | |
#include <stddef.h> | |
#include <stdint.h> | |
// Normalized WAV file header structure | |
typedef struct WAVHeader_t { | |
// Should contain the letters "RIFF" | |
char file_id[5]; | |
// The size of entire file in bytes, minus 8 bytes for chunk_id and | |
// chunk_size. | |
uint32_t file_size; | |
// Should contain the letters "WAVE" | |
char format[5]; | |
// Should contain the letters "fmt " | |
char subchunk_id[5]; | |
// 16 for PCM. This is the size of the rest of the sunchunk which follows this | |
// number. | |
uint32_t subchunk_size; | |
// PCM = 1, values other than 1 indicate some form of compression | |
uint16_t audio_format; | |
// mono = 1, stereo = 2, etc. | |
uint16_t number_of_channels; | |
// self-explanatory | |
uint32_t sample_rate; | |
// sample_rate * number of channels * bits per sample / 8 | |
uint32_t byte_rate; | |
// number of channels * bits per sample / 8. Number of bytes for one sample | |
// including all channels. | |
uint16_t block_align; | |
// self-explanatory. BITS, not BYTES. | |
uint16_t bits_per_sample; | |
// Should contain the letters "data" | |
char data_id[5]; | |
// number of samples * number of channels * bits per sample / 8 | |
// Actual number of bytes in the sound data. | |
uint32_t data_size; | |
} WAVHeader; | |
// WAV file with header and pointer to data | |
typedef struct WAVFile_t { | |
// WAV header (copy re-constructed from the file with proper byte aligment) | |
WAVHeader header; | |
// Pointer to audio data | |
uint8_t const* data; | |
// Length of data, copy of header.data_size field | |
uint32_t data_length; | |
} WAVFile; | |
// Parse the header of WAV file and return WAVFile structure with header and | |
// pointer to data | |
WAVFile WAV_ParseFileData(uint8_t const* data); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment