Imported Debian version 0.1.3.1
[deb_fdk-aac.git] / wavreader.c
CommitLineData
56e73ff7
DM
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
27struct 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
39static 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
48static 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
57static 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
64void* 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
131void wav_read_close(void* obj) {
132 struct wav_reader* wr = (struct wav_reader*) obj;
133 fclose(wr->wav);
134 free(wr);
135}
136
137int 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
152int 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