55#define MOD_NAME "[WAV reader] "
56#define WAV_MAX_BIT_DEPTH 64
57#define WAV_MAX_CHANNELS 128
59#define READ_N(buf, len) \
60 if (fread(buf, len, 1, wav_file) != 1) {\
61 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Read error: %s.\n", ug_strerror(errno));\
62 return WAV_HDR_PARSE_READ_ERROR;\
65#define GUID_PCM { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }
69 if (chunk_size != 16 && chunk_size != 18 && chunk_size != 40) {
76 if (format != 0x0001 && format != 0xFFFE) {
95 uint32_t avg_bytes_per_sec;
96 READ_N(&avg_bytes_per_sec,
sizeof(avg_bytes_per_sec));
98 uint16_t block_align_offset;
99 READ_N(&block_align_offset,
sizeof(block_align_offset));
101 uint16_t bits_per_sample;
102 READ_N(&bits_per_sample,
sizeof(bits_per_sample));
108 if (chunk_size >= 18) {
111 if (ext_size != chunk_size - 18) {
115 if (ext_size == 22) {
121 if (memcmp(guid, buffer, 16) != 0) {
129 if (format == 0xFFFE) {
137static _Bool
is_member(
const char *needle,
const char **haystack) {
138 while (*haystack != NULL) {
139 if (strncmp(needle, *haystack, 4) == 0) {
147static int fskip(FILE *f,
long off) {
152 if (getc(f) == EOF) {
162 if (!found_ds64_chunk) {
171 if (
_fseeki64(wav_file, 0, SEEK_END) != 0) {
175 if (data_end == -1) {
188 if (chunk_size < 28) {
195 assert(tmp <= LLONG_MAX);
198 uint32_t table_count = 0;
199 const size_t table_sz = (
sizeof(uint32_t) +
sizeof(uint64_t) );
201 assert(table_sz * table_count <=
MIN(
sizeof(uint32_t),
sizeof(
long)));
202 if (chunk_size - 28 != table_sz * table_count) {
204 table_count, chunk_size);
207 if (!
fskip(wav_file, (
long)(table_count * table_sz))) {
214#define CHECK(cmd, retval) if (cmd == -1) return retval;
223 if (strncmp(buffer,
"RF64", 4) == 0 || strncmp(buffer,
"BW64", 4) == 0) {
226 }
else if (strncmp(buffer,
"RIFF", 4) != 0) {
235 if (strncmp(buffer,
"WAVE", 4) != 0) {
240 bool found_data_chunk =
false;
241 bool found_ds64_chunk =
false;
242 bool found_fmt_chunk =
false;
243 while (fread(buffer, 4, 1, wav_file) == 1) {
245 if (strncmp(buffer,
"data", 4) == 0) {
249 found_data_chunk =
true;
252 if (strncmp(buffer,
"ds64", 4) == 0) {
253 if (!
read_ds64(wav_file, chunk_size, metadata)) {
256 found_ds64_chunk =
true;
257 }
else if (strncmp(buffer,
"fmt ", 4) == 0) {
258 found_fmt_chunk =
true;
264 const char *known_tags[] = {
"JUNK",
"LIST",
"id3 ", NULL };
266 log_msg(level,
MOD_NAME "Skipping chunk \"%4.4s\" sized %" PRIu32
" B!\n", buffer, chunk_size);
271 if (!found_data_chunk) {
276 if (!found_fmt_chunk) {
281 if (rf64 && !found_ds64_chunk) {
304 return "Wav header OK";
306 return "Premature end of WAV file";
308 return "Wav header in wrong format";
310 return "Wav not in PCM";
312 return "Wrong/unsupported value in header";
315 return "Unknown error";
321 if (whence == SEEK_CUR || whence == SEEK_END) {
322 return fseek(wav_file,
offset, whence);
324 assert(whence == SEEK_SET);
static __device__ const float offset
void log_msg(int level, const char *format,...)
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_VERBOSE
#define LOG_LEVEL_WARNING
less severe errors
void ug_perror(const char *s)
void signed2unsigned(char *out, const char *in, int in_len)
int wav_seek(FILE *wav_file, long offset, int whence, struct wav_metadata *metadata)
same as fseek but WAV header presence is respected (for SEEK SET)
#define WAV_MAX_BIT_DEPTH
static int fskip(FILE *f, long off)
static _Bool read_ds64(FILE *wav_file, uint32_t chunk_size, struct wav_metadata *metadata)
static _Bool process_data_chunk(FILE *wav_file, uint32_t chunk_size, struct wav_metadata *metadata, _Bool found_ds64_chunk)
const char * get_wav_error(int errcode)
size_t wav_read(void *buffer, size_t sample_count, FILE *wav_file, struct wav_metadata *metadata)
static _Bool is_member(const char *needle, const char **haystack)
#define CHECK(cmd, retval)
int read_wav_header(FILE *wav_file, struct wav_metadata *metadata)
static int read_fmt_chunk(FILE *wav_file, struct wav_metadata *metadata, size_t chunk_size)
#define WAV_HDR_PARSE_WRONG_FORMAT
#define WAV_HDR_PARSE_READ_ERROR
#define WAV_HDR_PARSE_INVALID_PARAM
#define WAV_HDR_PARSE_NOT_PCM