1 /* ------------------------------------------------------------------
2  * Copyright (C) 2009 Martin Storsjo
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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
13  * express or implied.
14  * See the License for the specific language governing permissions
15  * and limitations under the License.
16  * -------------------------------------------------------------------
17  */
18 
19 #include "wavreader.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdint.h>
24 
25 #define TAG(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
26 
27 struct wav_reader {
28 	FILE *wav;
29 	uint32_t data_length;
30 
31 	int format;
32 	int sample_rate;
33 	int bits_per_sample;
34 	int channels;
35 	int byte_rate;
36 	int block_align;
37 };
38 
read_tag(struct wav_reader * wr)39 static uint32_t read_tag(struct wav_reader* wr) {
40 	uint32_t tag = 0;
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);
45 	return tag;
46 }
47 
read_int32(struct wav_reader * wr)48 static uint32_t read_int32(struct wav_reader* wr) {
49 	uint32_t value = 0;
50 	value |= fgetc(wr->wav) <<  0;
51 	value |= fgetc(wr->wav) <<  8;
52 	value |= fgetc(wr->wav) << 16;
53 	value |= fgetc(wr->wav) << 24;
54 	return value;
55 }
56 
read_int16(struct wav_reader * wr)57 static uint16_t read_int16(struct wav_reader* wr) {
58 	uint16_t value = 0;
59 	value |= fgetc(wr->wav) << 0;
60 	value |= fgetc(wr->wav) << 8;
61 	return value;
62 }
63 
wav_read_open(const char * filename)64 void* wav_read_open(const char *filename) {
65 	struct wav_reader* wr = (struct wav_reader*) malloc(sizeof(*wr));
66 	long data_pos = 0;
67 	memset(wr, 0, sizeof(*wr));
68 
69 	wr->wav = fopen(filename, "rb");
70 	if (wr->wav == NULL) {
71 		free(wr);
72 		return NULL;
73 	}
74 
75 	while (1) {
76 		uint32_t tag, tag2, length;
77 		tag = read_tag(wr);
78 		if (feof(wr->wav))
79 			break;
80 		length = read_int32(wr);
81 		if (tag != TAG('R', 'I', 'F', 'F') || length < 4) {
82 			fseek(wr->wav, length, SEEK_CUR);
83 			continue;
84 		}
85 		tag2 = read_tag(wr);
86 		length -= 4;
87 		if (tag2 != TAG('W', 'A', 'V', 'E')) {
88 			fseek(wr->wav, length, SEEK_CUR);
89 			continue;
90 		}
91 		// RIFF chunk found, iterate through it
92 		while (length >= 8) {
93 			uint32_t subtag, sublength;
94 			subtag = read_tag(wr);
95 			if (feof(wr->wav))
96 				break;
97 			sublength = read_int32(wr);
98 			length -= 8;
99 			if (length < sublength)
100 				break;
101 			if (subtag == TAG('f', 'm', 't', ' ')) {
102 				if (sublength < 16) {
103 					// Insufficient data for 'fmt '
104 					break;
105 				}
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);
117 			} else {
118 				fseek(wr->wav, sublength, SEEK_CUR);
119 			}
120 			length -= sublength;
121 		}
122 		if (length > 0) {
123 			// Bad chunk?
124 			fseek(wr->wav, length, SEEK_CUR);
125 		}
126 	}
127 	fseek(wr->wav, data_pos, SEEK_SET);
128 	return wr;
129 }
130 
wav_read_close(void * obj)131 void wav_read_close(void* obj) {
132 	struct wav_reader* wr = (struct wav_reader*) obj;
133 	fclose(wr->wav);
134 	free(wr);
135 }
136 
wav_get_header(void * obj,int * format,int * channels,int * sample_rate,int * bits_per_sample,unsigned int * data_length)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;
139 	if (format)
140 		*format = wr->format;
141 	if (channels)
142 		*channels = wr->channels;
143 	if (sample_rate)
144 		*sample_rate = wr->sample_rate;
145 	if (bits_per_sample)
146 		*bits_per_sample = wr->bits_per_sample;
147 	if (data_length)
148 		*data_length = wr->data_length;
149 	return wr->format && wr->sample_rate;
150 }
151 
wav_read_data(void * obj,unsigned char * data,unsigned int length)152 int wav_read_data(void* obj, unsigned char* data, unsigned int length) {
153 	struct wav_reader* wr = (struct wav_reader*) obj;
154 	int n;
155 	if (wr->wav == NULL)
156 		return -1;
157 	if (length > wr->data_length)
158 		length = wr->data_length;
159 	n = fread(data, 1, length, wr->wav);
160 	wr->data_length -= length;
161 	return n;
162 }
163 
164