#include #include #include #include #include #include #include #include #include #include #include #include #define VERSION "0.1" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #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 \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; }