#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 wave_verify_riff(int fd, hdr_riff_t* hdr){ if(read(fd, hdr, sizeof(hdr_riff_t)) != sizeof(hdr_riff_t)){ fprintf(stderr, "Failed to read input data: %s\n", strerror(errno)); return 1; } if(memcmp(hdr->magic_riff, "RIFF", 4) || memcmp(hdr->magic_wave, "WAVE", 4)){ fprintf(stderr, "Invalid RIFF/WAVE magic - probably not a WAVE file\n"); return 1; } fprintf(stderr, "RIFF chunk size: %d\n", hdr->size); return 0; } int wave_verify_fmt(int fd, hdr_fmt_t* hdr){ uint16_t extra_data; uint8_t skip_byte; size_t n; if(read(fd, hdr, sizeof(hdr_fmt_t)) != sizeof(hdr_fmt_t)){ fprintf(stderr, "Failed to read input data: %s\n", strerror(errno)); return 1; } if(memcmp(hdr->magic, "fmt ", 4)){ fprintf(stderr, "Invalid format header magic - format probably incompatible\n"); return 1; } fprintf(stderr, "Format chunk size: %d\n", hdr->size); fprintf(stderr, "Format: %d\n", hdr->fmt); fprintf(stderr, "Channels: %d\n", hdr->channels); fprintf(stderr, "Samplerate: %d\n", hdr->sample_rate); fprintf(stderr, "Byterate: %d\n", hdr->byte_rate); fprintf(stderr, "Align: %d\n", hdr->bitdepth); fprintf(stderr, "Samplebits: %d\n", hdr->samplebits); if(hdr->fmt != 1){ if(read(fd, &extra_data, 2) != 2){ fprintf(stderr, "Failed to read input data: %s\n", strerror(errno)); return 1; } } else if(hdr->size > 16 /* length of fmt header as counted from after the size member */){ fprintf(stderr, "Skipping %d additional header bytes:", hdr->size - 16); for(n = 16; n < hdr->size; n++){ if(read(fd, &skip_byte, 1) != 1){ fprintf(stderr, "Failed to read input data: %s\n", strerror(errno)); return 1; } fprintf(stderr, " %02X", skip_byte); } fprintf(stderr, "\n"); } return 0; } int wave_verify_data(int fd, hdr_data_t* hdr){ 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; } if(memcmp(hdr->magic, "data", 4)){ fprintf(stderr, "Invalid data magic\n"); return 1; } fprintf(stderr, "%d bytes of sample data in file\n", hdr->size); return 0; } 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; hdr_fmt_t fmt; hdr_data_t data; if(wave_verify_riff(source_fd, &riff)){ close(source_fd); return EXIT_FAILURE; } if(wave_verify_fmt(source_fd, &fmt)){ close(source_fd); return EXIT_FAILURE; } if(wave_verify_data(source_fd, &data)){ close(source_fd); return EXIT_FAILURE; } /* 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; } uint16_t sample; uint8_t channel = 0; for(n = 0; n < data.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, "Done, exported %ld frames of data %d channels, processed %ld samples\n", n, fmt.channels, fmt.channels * n); return EXIT_SUCCESS; }