diff options
Diffstat (limited to 'wavextract.c')
-rw-r--r-- | wavextract.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/wavextract.c b/wavextract.c new file mode 100644 index 0000000..4192f64 --- /dev/null +++ b/wavextract.c @@ -0,0 +1,180 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdint.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <inttypes.h> +#include <math.h> +#include <ctype.h> + +#define VERSION "0.1" + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include <windows.h> + #define PRIsize_t "Iu" + #define htole16(x) (x) + #define htole32(x) (x) +#else + #define PRIsize_t "lu" +#endif + +#pragma pack(push, 1) +typedef struct /*_chunk_riff*/ { + char magic_riff[4]; + uint32_t size; + char magic_wave[4]; +} hdr_riff_t; + +typedef struct /*_chunk_fmt_base*/ { + char magic[4]; + uint32_t size; + uint16_t fmt; + uint16_t channels; + uint32_t sample_rate; + uint32_t byte_rate; //(samplerate * sampleBits * channels) / 8. + uint16_t bitdepth; //(sampleBits * channels) / 8 + uint16_t samplebits; + //uint16_t extsize; //only present if fmt != 1 +} hdr_fmt_t; + +typedef struct /*_chunk_fact*/ { + char magic[4]; + uint32_t size; + uint32_t samples; +} hdr_fact_t; + +typedef struct /*_chunk_data*/ { + char magic[4]; + uint32_t size; +} hdr_data_t; +#pragma pack(pop) + +static int usage(char* fn){ + fprintf(stdout, "wavextract " VERSION " - Convert WAVE files to CSV sample data\n"); + fprintf(stdout, "\tUsage: %s <file.wav>\n\n", fn); + //fprintf(stdout, "Supported wave formats: i8, i16 (default), i32, f32, nf32\n"); + return EXIT_FAILURE; +} + +int main(int argc, char** argv){ + size_t n; + #ifdef _WIN32 + _fmode = _O_BINARY; + #endif + + if(argc < 2){ + return usage(argv[0]); + } + + fprintf(stderr, "Opening wave input file %s\n", argv[1]); + int source_fd = open(argv[1], O_RDONLY); + if(source_fd < 0){ + fprintf(stderr, "Failed to open input file %s: %s\n", argv[1], strerror(errno)); + return EXIT_FAILURE; + } + + hdr_riff_t riff; + if(read(source_fd, &riff, sizeof(riff)) != sizeof(riff)){ + close(source_fd); + fprintf(stderr, "Failed to read input data: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + if(memcmp(riff.magic_riff, "RIFF", 4) || memcmp(riff.magic_wave, "WAVE", 4)){ + close(source_fd); + fprintf(stderr, "Invalid RIFF/WAVE magic\n"); + return EXIT_FAILURE; + } + + fprintf(stderr, "Chunk size: %d\n", riff.size); + + hdr_fmt_t fmt; + uint16_t extra_data; + if(read(source_fd, &fmt, sizeof(fmt)) != sizeof(fmt)){ + close(source_fd); + fprintf(stderr, "Failed to read input data: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + if(memcmp(fmt.magic, "fmt ", 4)){ + close(source_fd); + fprintf(stderr, "Invalid format magic\n"); + return EXIT_FAILURE; + } + + fprintf(stderr, "Format chunk size: %d\n", fmt.size); + fprintf(stderr, "Format: %d\n", fmt.fmt); + fprintf(stderr, "Channels: %d\n", fmt.channels); + fprintf(stderr, "Samplerate: %d\n", fmt.sample_rate); + fprintf(stderr, "Byterate: %d\n", fmt.byte_rate); + fprintf(stderr, "Align: %d\n", fmt.bitdepth); + fprintf(stderr, "Samplebits: %d\n", fmt.samplebits); + + if(fmt.fmt != 1){ + read(source_fd, &extra_data, 2); + } + + if(fmt.fmt == 1 && fmt.size > 16){ + fprintf(stderr, "Skipping %d additional header bytes\n", fmt.size - 16); + for(n = 16; n < fmt.size; n++){ + read(source_fd, &extra_data, 1); + } + } + + /* For now, just skip further analysis and bail on incompatible format */ + if(fmt.samplebits != 16){ + close(source_fd); + fprintf(stderr, "This format is currently not supported\n"); + return EXIT_FAILURE; + } + + hdr_data_t data_header; + if(read(source_fd, &data_header, sizeof(data_header)) != sizeof(data_header)){ + close(source_fd); + fprintf(stderr, "Failed to read input data: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + if(memcmp(data_header.magic, "data", 4)){ + close(source_fd); + fprintf(stderr, "Invalid data magic\n"); + return EXIT_FAILURE; + } + + fprintf(stderr, "%d bytes of sample data in file\n", data_header.size); + + uint16_t sample; + uint8_t channel = 0; + + for(n = 0; n < data_header.size / 2; n++){ + //read sample + if(read(source_fd, &sample, 2) != 2){ + close(source_fd); + fprintf(stderr, "Failed to read input data at sample %ld: %s\n", n, strerror(errno)); + return EXIT_FAILURE; + } + + if(channel == 0){ + printf("%ld,%d", n, (int16_t) sample); + } + else{ + printf(",%d", (int16_t) sample); + } + + if(channel == fmt.channels - 1){ + printf("\n"); + } + + channel += 1; + channel %= fmt.channels; + } + + close(source_fd); + fprintf(stderr, "All done\n"); + return EXIT_SUCCESS; +} |