fixed off-by-one bug
[swftools.git] / lib / wav.c
blob5bd30d7921fdb3fec1e89e2bc7923f505c2363bd
1 /* wav.c
2 Routines for handling .wav files
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "wav.h"
27 struct WAVBlock {
28 char id[5];
29 unsigned int size;
32 int getWAVBlock(FILE*fi, struct WAVBlock*block)
34 unsigned int size;
35 unsigned char b[4];
36 if(fread(block->id,1,4,fi)<4)
37 return 0;
38 block->id[4] = 0;
39 if(fread(b,1,4,fi)<4)
40 return 0;
41 block->size = b[0]|b[1]<<8|b[2]<<16|b[3]<<24;
42 /*printf("Chunk: [%c%c%c%c] (%d bytes)\n",
43 block->id[0],block->id[1],
44 block->id[2],block->id[3],
45 block->size);*/
46 return 1;
49 int wav_read(struct WAV*wav, const char* filename)
51 FILE*fi = fopen(filename, "rb");
52 unsigned char b[16];
53 long int filesize;
54 struct WAVBlock block;
55 long int pos;
57 if(!fi)
58 return 0;
59 fseek(fi, 0, SEEK_END);
60 filesize = ftell(fi);
61 fseek(fi, 0, SEEK_SET);
63 //printf("Filesize: %d\n", filesize);
65 if(!getWAVBlock (fi, &block))
67 fclose(fi);
68 return 0;
70 if(strncmp(block.id,"RIFF",4))
72 fprintf(stderr, "wav_read: not a WAV file\n");
73 fclose(fi);
74 return 0;
76 if(block.size + 8 < filesize)
77 fprintf(stderr, "wav_read: warning - more tags (%lu extra bytes)\n", filesize - block.size - 8);
79 if(block.size == filesize)
80 /* some buggy software doesn't generate the right tag length */
81 block.size = filesize - 8;
83 if(block.size + 8 > filesize)
84 fprintf(stderr, "wav_read: warning - short file (%lu bytes missing)\n", block.size + 8 - filesize);
85 if(fread(b, 1, 4, fi) < 4)
87 fclose(fi);
88 return 0;
90 if(strncmp((const char*)b, "WAVE", 4))
92 fprintf(stderr, "wav_read: not a WAV file (2)\n");
93 fclose(fi);
94 return 0;
99 getWAVBlock(fi, &block);
100 pos = ftell(fi);
101 if(!strncmp(block.id, "fmt ", 4))
103 if(fread(&b, 1, 16, fi)<16)
105 fclose(fi);
106 return 0;
108 wav->tag = b[0]|b[1]<<8;
109 wav->channels = b[2]|b[3]<<8;
110 wav->sampsPerSec = b[4]|b[5]<<8|b[6]<<16|b[7]<<24;
111 wav->bytesPerSec = b[8]|b[9]<<8|b[10]<<16|b[11]<<24;
112 wav->align = b[12]|b[13]<<8;
113 wav->bps = b[14]|b[15]<<8;
115 else
116 if (!strncmp(block.id, "LIST", 4))
118 // subchunk ICMT (comment) may exist
120 else
121 if (!strncmp(block.id, "data", 4))
123 int l;
124 wav->data = (unsigned char*)malloc(block.size);
125 if(!wav->data)
127 fprintf(stderr, "Out of memory (%d bytes needed)", block.size);
128 fclose(fi);
129 return 0;
131 l = fread(wav->data, 1, block.size, fi);
132 if(l<=0) {
133 fprintf(stderr, "Error: Couldn't read WAV data block\n");
134 fclose(fi);
135 return 0;
136 } else if(l < block.size)
138 fprintf(stderr, "Warning: data block of size %d is only %d bytes (%d bytes missing)\n", block.size, l, block.size-l);
139 wav->size = l;
140 } else {
141 wav->size = block.size;
144 pos+=block.size;
145 fseek(fi, pos, SEEK_SET);
147 while (pos < filesize);
148 fclose(fi);
149 return 1;
152 int wav_write(struct WAV*wav, const char*filename)
154 FILE*fi = fopen(filename, "wb");
155 char*b="RIFFWAVEfmt \x10\0\0\0data";
156 char c[16];
157 unsigned long int w32;
158 if(!fi)
159 return 0;
160 fwrite(b, 4, 1, fi);
161 w32=(/*fmt*/8+0x10+/*data*/8+wav->size);
162 c[0] = w32;
163 c[1] = w32>>8;
164 c[2] = w32>>16;
165 c[3] = w32>>24;
166 fwrite(c, 4, 1, fi);
167 fwrite(&b[4], 12, 1, fi);
168 c[0] = wav->tag;
169 c[1] = wav->tag>>8;
170 c[2] = wav->channels;
171 c[3] = wav->channels>>8;
172 c[4] = wav->sampsPerSec;
173 c[5] = wav->sampsPerSec>>8;
174 c[6] = wav->sampsPerSec>>16;
175 c[7] = wav->sampsPerSec>>24;
176 c[8] = wav->bytesPerSec;
177 c[9] = wav->bytesPerSec>>8;
178 c[10] = wav->bytesPerSec>>16;
179 c[11] = wav->bytesPerSec>>24;
180 c[12] = wav->align;
181 c[13] = wav->align>>8;
182 c[14] = wav->bps;
183 c[15] = wav->bps>>8;
184 fwrite(c, 16, 1, fi);
185 fwrite(&b[16], 4, 1, fi);
186 c[0] = wav->size;
187 c[1] = wav->size>>8;
188 c[2] = wav->size>>16;
189 c[3] = wav->size>>24;
190 fwrite(c,4,1,fi);
191 printf("writing %d converted bytes\n", wav->size);
192 fwrite(wav->data,wav->size,1,fi);
193 fclose(fi);
194 return 1;
197 void wav_print(struct WAV*wav)
199 printf("tag:%04x channels:%d samples/sec:%lu bytes/sec:%lu align:%d bits/sample:%d size:%d\n",
200 wav->tag, wav->channels, wav->sampsPerSec, wav->bytesPerSec,
201 wav->align, wav->bps, wav->size);
204 int wav_convert2mono(struct WAV*src, struct WAV*dest, int rate)
206 int samplelen=src->size/src->align;
207 int bps=src->bps;
208 double ratio;
209 double pos = 0;
210 int pos2 = 0;
211 int channels=src->channels;
212 int i;
213 int fill;
215 dest->sampsPerSec = rate;
216 dest->bps = 16;
217 dest->channels = 1;
218 dest->align = 2;
219 dest->tag = src->tag;
220 dest->bytesPerSec = dest->sampsPerSec*dest->align;
222 ratio = (double)dest->sampsPerSec/(double)src->sampsPerSec;
223 fill = (int)(ratio+1)*2;
225 dest->data = (unsigned char*)malloc((int)(samplelen*ratio*2)+128);
226 if(!dest->data)
227 return 0;
228 dest->size = (int)(samplelen*ratio)*2;
230 if(bps == 8) {
231 if(ratio <= 1) {
232 for(i=0; i<src->size; i+=channels) {
233 int pos2 = ((int)pos)*2;
234 dest->data[pos2] = 0;
235 dest->data[pos2+1] = src->data[i]+128;
236 pos += ratio;
238 } else {
239 for(i=0; i<src->size; i+=channels) {
240 int j;
241 int pos2 = ((int)pos)*2;
242 for(j=0;j<fill;j+=2) {
243 dest->data[pos2+j+0] = 0;
244 dest->data[pos2+j+1] = src->data[i]+128;
246 pos += ratio;
249 } else if(bps == 16) {
250 if(ratio <= 1) {
251 for(i=0; i<src->size/2; i+=channels) {
252 int pos2 = ((int)pos)*2;
253 dest->data[pos2+0]=src->data[i*2];
254 dest->data[pos2+1]=src->data[i*2+1];
255 pos += ratio;
257 } else {
258 for(i=0; i<src->size/2; i+=channels) {
259 int j;
260 int pos2 = ((int)pos)*2;
261 for(j=0;j<fill;j+=2) {
262 dest->data[pos2+j+0] = src->data[i*2];
263 dest->data[pos2+j+1] = src->data[i*2+1];
265 pos += ratio;
268 } else if(bps == 32) {
269 if(ratio <= 1) {
270 for(i=0; i<src->size/4; i+=channels) {
271 int pos2 = ((int)pos)*2;
272 dest->data[pos2+0]=src->data[i*4+2];
273 dest->data[pos2+1]=src->data[i*4+3];
274 pos += ratio;
276 } else {
277 for(i=0; i<src->size/4; i+=channels) {
278 int j;
279 int pos2 = ((int)pos)*2;
280 for(j=0;j<fill;j+=2) {
281 dest->data[pos2+j+0] = src->data[i*4+2];
282 dest->data[pos2+j+1] = src->data[i*4+3];
284 pos += ratio;
287 } else {
288 fprintf(stderr, "Unsupported bitspersample value: %d\n", bps);
290 return 1;