From b93d8362bea9621a5e18b648a6fa6c8541b5bfbc Mon Sep 17 00:00:00 2001 From: cbdev Date: Tue, 3 Oct 2023 21:18:11 +0200 Subject: Implement floating point sample format --- wavextract.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 75 insertions(+), 20 deletions(-) diff --git a/wavextract.c b/wavextract.c index 627406a..2198989 100644 --- a/wavextract.c +++ b/wavextract.c @@ -7,7 +7,7 @@ #include #include -#define VERSION "0.1" +#define VERSION "0.2" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -48,12 +48,20 @@ typedef struct /*_chunk_data*/ { char magic[4]; uint32_t size; } hdr_data_t; + +typedef union { + int32_t i32; + int16_t i16; + float f32; + double f64; + uint8_t bytes[8]; +} sample_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 \n\n", fn); - //fprintf(stdout, "Supported wave formats: i8, i16 (default), i32, f32, nf32\n"); + fprintf(stdout, "Supported wave formats: PCM s16le, s32le, f32, f64\n"); return EXIT_FAILURE; } @@ -116,7 +124,23 @@ int wave_verify_fmt(int fd, hdr_fmt_t* hdr){ return 0; } -int wave_verify_data(int fd, hdr_data_t* hdr){ +int wave_verify_fact(int fd, hdr_fact_t* hdr){ + if(read(fd, hdr, sizeof(hdr_fact_t)) != sizeof(hdr_fact_t)){ + fprintf(stderr, "Failed to read input data: %s\n", strerror(errno)); + return 1; + } + + if(memcmp(hdr->magic, "fact", 4)){ + fprintf(stderr, "Invalid data magic\n"); + return 1; + } + + fprintf(stderr, "Fact chunk size: %d\n", hdr->size); + fprintf(stderr, "%d samples per channel\n", hdr->samples); + return 0; +} + +int wave_verify_data(int fd, hdr_data_t* hdr, size_t sample_bits, size_t channels){ if(read(fd, hdr, sizeof(hdr_data_t)) != sizeof(hdr_data_t)){ fprintf(stderr, "Failed to read input data: %s\n", strerror(errno)); return 1; @@ -128,11 +152,39 @@ int wave_verify_data(int fd, hdr_data_t* hdr){ } fprintf(stderr, "%d bytes of sample data in file\n", hdr->size); + if(hdr->size % (sample_bits / 8 * channels)){ + fprintf(stderr, "Sample data unaligned, unable to decode\n"); + return 1; + } + fprintf(stderr, "Data chunk maps to %" PRIsize_t " samples of data per channel\n", hdr->size / (sample_bits / 8 * channels)); return 0; } +int print_sample(sample_t sample, uint16_t format, uint16_t samplebits){ + if(format == 1){ + if(samplebits == 16){ + printf(",%d", sample.i16); + return 0; + } + else if(samplebits == 32){ + printf(",%d", sample.i32); + return 0; + } + } + else if(format == 3){ + if(samplebits == 32){ + printf(",%.9g", sample.f32); + return 0; + } + else if(samplebits == 64){ + printf(",%.17g", sample.f64); + return 0; + } + } + return 1; +} + int main(int argc, char** argv){ - size_t n; #ifdef _WIN32 _fmode = _O_BINARY; #endif @@ -150,48 +202,51 @@ int main(int argc, char** argv){ hdr_riff_t riff; hdr_fmt_t fmt; + hdr_fact_t fact; hdr_data_t data; - if(wave_verify_riff(source_fd, &riff)){ + if(wave_verify_riff(source_fd, &riff) || wave_verify_fmt(source_fd, &fmt)){ close(source_fd); return EXIT_FAILURE; } - if(wave_verify_fmt(source_fd, &fmt)){ + //non-pcm formats have an additional fact header + if(fmt.fmt != 1 && wave_verify_fact(source_fd, &fact)){ close(source_fd); return EXIT_FAILURE; } - if(wave_verify_data(source_fd, &data)){ + if(wave_verify_data(source_fd, &data, fmt.samplebits, fmt.channels)){ close(source_fd); return EXIT_FAILURE; } - /* For now, just skip further analysis and bail on incompatible format */ - if(fmt.samplebits != 16){ + //compression currently unsupported + if((fmt.fmt != 1 && fmt.fmt != 3) || fmt.samplebits / 8 > sizeof(sample_t)){ close(source_fd); fprintf(stderr, "This format is currently not supported\n"); - return EXIT_FAILURE; + return EXIT_FAILURE; } - uint16_t sample; - uint8_t channel = 0; + sample_t sample; + size_t channel = 0; + size_t sample_offset = 0; - for(n = 0; n < data.size / 2; n++){ + for(sample_offset = 0; sample_offset < data.size / (fmt.samplebits / 8 * fmt.channels); sample_offset++){ //read sample - if(read(source_fd, &sample, 2) != 2){ + //TODO endianness conversion + if(read(source_fd, &sample, fmt.samplebits / 8) != fmt.samplebits / 8){ close(source_fd); - fprintf(stderr, "Failed to read input data at sample %" PRIsize_t ": %s\n", n, strerror(errno)); + fprintf(stderr, "Failed to read input data at sample %" PRIsize_t ": %s\n", sample_offset, strerror(errno)); return EXIT_FAILURE; } if(channel == 0){ - printf("%" PRIsize_t ",%d", n, (int16_t) sample); - } - else{ - printf(",%d", (int16_t) sample); + printf("%" PRIsize_t "", sample_offset); } + print_sample(sample, fmt.fmt, fmt.samplebits); + if(channel == fmt.channels - 1){ printf("\n"); } @@ -201,6 +256,6 @@ int main(int argc, char** argv){ } close(source_fd); - fprintf(stderr, "Done, exported %" PRIsize_t " frames of data %d channels, processed %" PRIsize_t " samples\n", n, fmt.channels, fmt.channels * n); + fprintf(stderr, "Done, exported %" PRIsize_t " frames of data %d channels, processed %" PRIsize_t " samples\n", sample_offset, fmt.channels, fmt.channels * sample_offset); return EXIT_SUCCESS; } -- cgit v1.2.3