summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2023-10-03 21:18:11 +0200
committercbdev <cb@cbcdn.com>2023-10-03 21:18:11 +0200
commitb93d8362bea9621a5e18b648a6fa6c8541b5bfbc (patch)
tree24f4f976d6fe305dc4e6cdb058bcb62001026ee7
parent25188a3bb756efc9fa13b552f3d2c8ba3d05e69c (diff)
downloadwavextract-b93d8362bea9621a5e18b648a6fa6c8541b5bfbc.tar.gz
wavextract-b93d8362bea9621a5e18b648a6fa6c8541b5bfbc.tar.bz2
wavextract-b93d8362bea9621a5e18b648a6fa6c8541b5bfbc.zip
Implement floating point sample format
-rw-r--r--wavextract.c95
1 files 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 <fcntl.h>
#include <inttypes.h>
-#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 <file.wav>\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;
}