1 /* ------------------------------------------------------------------
2 * Copyright (C) 2009 Martin Storsjo
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
19 #include "wavreader.h"
25 #define TAG(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
39 static uint32_t read_tag(struct wav_reader
* wr
) {
41 tag
= (tag
<< 8) | fgetc(wr
->wav
);
42 tag
= (tag
<< 8) | fgetc(wr
->wav
);
43 tag
= (tag
<< 8) | fgetc(wr
->wav
);
44 tag
= (tag
<< 8) | fgetc(wr
->wav
);
48 static uint32_t read_int32(struct wav_reader
* wr
) {
50 value
|= fgetc(wr
->wav
) << 0;
51 value
|= fgetc(wr
->wav
) << 8;
52 value
|= fgetc(wr
->wav
) << 16;
53 value
|= fgetc(wr
->wav
) << 24;
57 static uint16_t read_int16(struct wav_reader
* wr
) {
59 value
|= fgetc(wr
->wav
) << 0;
60 value
|= fgetc(wr
->wav
) << 8;
64 void* wav_read_open(const char *filename
) {
65 struct wav_reader
* wr
= (struct wav_reader
*) malloc(sizeof(*wr
));
67 memset(wr
, 0, sizeof(*wr
));
69 wr
->wav
= fopen(filename
, "rb");
70 if (wr
->wav
== NULL
) {
76 uint32_t tag
, tag2
, length
;
80 length
= read_int32(wr
);
81 if (tag
!= TAG('R', 'I', 'F', 'F') || length
< 4) {
82 fseek(wr
->wav
, length
, SEEK_CUR
);
87 if (tag2
!= TAG('W', 'A', 'V', 'E')) {
88 fseek(wr
->wav
, length
, SEEK_CUR
);
91 // RIFF chunk found, iterate through it
93 uint32_t subtag
, sublength
;
94 subtag
= read_tag(wr
);
97 sublength
= read_int32(wr
);
99 if (length
< sublength
)
101 if (subtag
== TAG('f', 'm', 't', ' ')) {
102 if (sublength
< 16) {
103 // Insufficient data for 'fmt '
106 wr
->format
= read_int16(wr
);
107 wr
->channels
= read_int16(wr
);
108 wr
->sample_rate
= read_int32(wr
);
109 wr
->byte_rate
= read_int32(wr
);
110 wr
->block_align
= read_int16(wr
);
111 wr
->bits_per_sample
= read_int16(wr
);
112 fseek(wr
->wav
, sublength
- 16, SEEK_CUR
);
113 } else if (subtag
== TAG('d', 'a', 't', 'a')) {
114 data_pos
= ftell(wr
->wav
);
115 wr
->data_length
= sublength
;
116 fseek(wr
->wav
, sublength
, SEEK_CUR
);
118 fseek(wr
->wav
, sublength
, SEEK_CUR
);
124 fseek(wr
->wav
, length
, SEEK_CUR
);
127 fseek(wr
->wav
, data_pos
, SEEK_SET
);
131 void wav_read_close(void* obj
) {
132 struct wav_reader
* wr
= (struct wav_reader
*) obj
;
137 int wav_get_header(void* obj
, int* format
, int* channels
, int* sample_rate
, int* bits_per_sample
, unsigned int* data_length
) {
138 struct wav_reader
* wr
= (struct wav_reader
*) obj
;
140 *format
= wr
->format
;
142 *channels
= wr
->channels
;
144 *sample_rate
= wr
->sample_rate
;
146 *bits_per_sample
= wr
->bits_per_sample
;
148 *data_length
= wr
->data_length
;
149 return wr
->format
&& wr
->sample_rate
;
152 int wav_read_data(void* obj
, unsigned char* data
, unsigned int length
) {
153 struct wav_reader
* wr
= (struct wav_reader
*) obj
;
157 if (length
> wr
->data_length
)
158 length
= wr
->data_length
;
159 n
= fread(data
, 1, length
, wr
->wav
);
160 wr
->data_length
-= length
;