1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
/**
* Copyright (c) 2018 chai
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include "wav.h"
typedef unsigned short Uint16;
typedef unsigned int Uint32;
static const char *findSubChunk(
const char *data, size_t len, const char *id, size_t *size
) {
/* TODO : Error handling on malformed wav file */
size_t idLen = strlen(id);
const char *p = data + 12;
next:
*size = *((Uint32*)(p + 4));
if (memcmp(p, id, idLen)) {
p += 8 + *size;
if (p > data + len) return NULL;
goto next;
}
return p + 8;
}
int wav_read(wav_t *w, const void *data, size_t len) {
int bitdepth, channels, samplerate, format;
size_t sz;
const char *p = (const char*)data;
memset(w, 0, sizeof(*w));
/* Check header */
if (memcmp(p, "RIFF", 4) || memcmp(p + 8, "WAVE", 4)) {
return WAV_EBADHEADER;
}
/* Find fmt subchunk */
p = findSubChunk((const char*)data, len, "fmt", &sz);
if (!p) return WAV_ENOFMT;
/* Load fmt info */
format = *((Uint16*)(p));
channels = *((Uint16*)(p + 2));
samplerate = *((Uint32*)(p + 4));
bitdepth = *((Uint16*)(p + 14));
if (format != 1) {
return WAV_ENOSUPPORT;
}
if (channels == 0 || samplerate == 0 || bitdepth == 0) {
return WAV_EBADFMT;
}
/* Find data subchunk */
p = findSubChunk((const char*)data, len, "data", &sz);
if (!p) return WAV_ENODATA;
/* copy p to new buffer */
char* buffer = (char*)malloc(sz);
memmove(buffer, p, sz);
/* Init wav_t struct */
w->data = buffer;
w->samplerate = samplerate;
w->channels = channels;
w->length = (sz / (bitdepth / 8)) / channels;
w->bitdepth = bitdepth;
/* Done! */
return WAV_ESUCCESS;
}
const char *wav_strerror(int err) {
switch (err) {
case WAV_ESUCCESS: return "success";
case WAV_EFAILURE: return "failure";
case WAV_EBADHEADER: return "bad header data";
case WAV_EBADFMT: return "bad fmt data";
case WAV_ENOFMT: return "missing 'fmt' subchunk";
case WAV_ENODATA: return "missing 'data' subchunk";
case WAV_ENOSUPPORT: return "unsupported format; "
"expected uncompressed PCM";
}
return "unknown error";
}
|