10 // http://mathmatrix.narod.ru/Wavefmt.html
11 char magic
[4]; // "RIFF"
12 uint32_t size
; // size of file
13 char wave_magic
[4]; // "WAVE"
14 char fmt_magic
[4]; // "fmt "
15 uint32_t wave_section_chunk_size
;
16 uint16_t wave_fmt_type
; // 1 = linear quantization
19 uint32_t bytes_per_second
;
21 uint16_t bits_per_sample
;
26 char name
[4]; // name of chunk
27 uint32_t size
; // size (bytes) of chunk (excluding header)
30 pure
int waveformat_get_sample_size(const struct waveformat
*restrict wf
)
32 return (wf
->bits
/ 8) * wf
->channels
;
35 static err_t
read_header(struct wavefile
*wav
)
41 if (fread(&whdr
, sizeof whdr
, 1, wav
->f
) < 1){
42 return make_error(EFREAD
, wav
, "%s: could not read wave file header", wav
->filename
);
45 // check wave magic strings
46 if (strncmp(whdr
.magic
, "RIFF", 4)
47 || strncmp(whdr
.wave_magic
, "WAVE", 4)
48 || strncmp(whdr
.fmt_magic
, "fmt ", 4)){
49 // invalid file format
50 return make_error(EFORMAT
, wav
, "%s: invalid wave file format", wav
->filename
);
53 // make sure it's in PCM format
54 if (whdr
.wave_fmt_type
!= 1){
55 return make_error(EFORMAT
, wav
, "%s: unsupported wave file format", wav
->filename
);
58 // store format information
59 wav
->format
.srate
= whdr
.srate
;
60 wav
->format
.bits
= whdr
.bits_per_sample
;
61 wav
->format
.channels
= whdr
.n_channels
;
65 if (fread(&chdr
, sizeof chdr
, 1, wav
->f
) < 1){
69 if (!strncmp(chdr
.name
, "data", 4)){
70 // found the data chunk
73 // this is not the data.
75 fseek(wav
->f
, chdr
.size
, SEEK_CUR
);
79 wav
->length
= chdr
.size
/ ((wav
->format
.bits
/ 8) * wav
->format
.channels
);
80 wav
->pcm_start
= ftell(wav
->f
);
84 err_t
wavefile_open(struct wavefile
*wav
, const char *filename
)
87 wav
->filename
= filename
; // TODO: dup?
88 wav
->f
= fopen(filename
, "r");
90 return make_error(EFOPEN
, wav
, "%s: cannot open file", filename
);
93 // read wave file header
94 return read_header(wav
);
97 err_t
wavefile_read_at(struct wavefile
*wav
, off_t sample_start
, void *buf
, size_t n_samples
)
99 if (sample_start
+ n_samples
> wav
->length
){
100 // past the end of file
101 return make_error(EWAVE_EOF
, wav
, "%s: tried reading beyond the end of the file (at sample number %llu)",
103 (unsigned long long) sample_start
);
106 fseek(wav
->f
, wav
->pcm_start
+ sample_start
* waveformat_get_sample_size(&wav
->format
), SEEK_SET
);
107 fread(buf
, 1, n_samples
* waveformat_get_sample_size(&wav
->format
), wav
->f
);