FreeCalypso > hg > gsm-codec-lib
comparison libtest/wavreader.c @ 7:634df6435e16
libtest: WAV reader and writer code from opencore-amr-0.1.6/test
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 19 Nov 2022 22:50:08 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
6:b2255a5d0519 | 7:634df6435e16 |
---|---|
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 |