moved from ../src/
[swftools.git] / lib / wav.c
1 /* wav.c
2    Routines for handling .wav files
3
4    Part of the swftools package.
5    
6    Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
7  
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.
12
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.
17
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 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "wav.h"
26
27 struct WAVBlock {
28     char id[4];
29     unsigned int size;
30 };
31
32 int getWAVBlock(FILE*fi, struct WAVBlock*block)
33 {
34     unsigned int size;
35     unsigned char b[4];
36     if(fread(block->id,1,4,fi)<4)
37         return 0;
38     if(fread(b,1,4,fi)<4)
39         return 0;
40     block->size = b[0]|b[1]<<8|b[2]<<16|b[3]<<24;
41     /*printf("Chunk: [%c%c%c%c] (%d bytes)\n", 
42             block->id[0],block->id[1],
43             block->id[2],block->id[3],
44             block->size);*/
45     return 1;
46 }
47
48 int readWAV(char* filename, struct WAV*wav)
49 {
50     FILE*fi = fopen(filename, "rb");
51     unsigned char b[16];
52     long int filesize;
53     struct WAVBlock block;
54     long int pos;
55     if(!fi)
56         return 0;
57     fseek(fi, 0, SEEK_END);
58     filesize = ftell(fi);
59     fseek(fi, 0, SEEK_SET);
60
61     //printf("Filesize: %d\n", filesize);
62
63     if(!getWAVBlock (fi, &block))
64         return 0;
65     if(strncmp(block.id,"RIFF",4)) {
66         fprintf(stderr, "readWAV: not a WAV file\n");
67         return 0;
68     }
69     if(block.size + 8 < filesize)
70         fprintf(stderr, "readWAV: warning - more tags (%d extra bytes)\n",
71                 filesize - block.size - 8);
72     if(block.size + 8 > filesize)
73         fprintf(stderr, "readWAV: warning - short file (%d bytes missing)\n",
74                 block.size + 8 -  filesize);
75     if(fread(b, 1, 4, fi) < 4) {
76         return 0;
77     }
78     if(strncmp(b, "WAVE", 4)) {
79         fprintf(stderr, "readWAV: not a WAV file (2)\n");
80         return 0;
81     }
82  
83     do
84     {
85         getWAVBlock(fi, &block);
86         pos = ftell(fi);
87         if(!strncmp(block.id, "fmt ", 4)) {
88             if(fread(&b, 1, 16, fi)<16)
89                 return 0;
90             wav->tag = b[0]|b[1]<<8;
91             wav->channels = b[2]|b[3]<<8;
92             wav->sampsPerSec = b[4]|b[5]<<8|b[6]<<16|b[7]<<24;
93             wav->bytesPerSec = b[8]|b[9]<<8|b[10]<<16|b[11]<<24;
94             wav->align = b[12]|b[13]<<8;
95             wav->bps = b[14]|b[15]<<8;
96         } else if (!strncmp(block.id, "LIST", 4)) {
97             // subchunk ICMT (comment) may exist
98         } else if (!strncmp(block.id, "data", 4)) {
99             wav->data = malloc(block.size);
100             if(!wav->data) {
101                 fprintf(stderr, "Out of memory (%d bytes needed)", block.size);
102                 return 0;
103             }
104             if(fread(wav->data, 1, block.size, fi) < block.size)
105                 return 0;
106             wav->size = block.size;
107         }
108         pos+=block.size;
109         fseek(fi, pos, SEEK_SET);
110     }
111     while (pos < filesize);
112
113     return 1;
114 }
115
116 int writeWAV(char*filename, struct WAV*wav)
117 {
118     FILE*fi = fopen(filename, "wb");
119     char*b="RIFFWAVEfmt \x10\0\0\0data";
120     char c[16];
121     unsigned long int w32;
122     if(!fi)
123         return 0;
124     fwrite(b, 4, 1, fi);
125     w32=(/*fmt*/8+0x10+/*data*/8+wav->size);
126     c[0] = w32;
127     c[1] = w32>>8;
128     c[2] = w32>>16;
129     c[3] = w32>>24;
130     fwrite(c, 4, 1, fi);
131     fwrite(&b[4], 12, 1, fi);
132     c[0] = wav->tag;
133     c[1] = wav->tag>>8;
134     c[2] = wav->channels;
135     c[3] = wav->channels>>8;
136     c[4] = wav->sampsPerSec;
137     c[5] = wav->sampsPerSec>>8;
138     c[6] = wav->sampsPerSec>>16;
139     c[7] = wav->sampsPerSec>>24;
140     c[8] = wav->bytesPerSec;
141     c[9] = wav->bytesPerSec>>8;
142     c[10] = wav->bytesPerSec>>16;
143     c[11] = wav->bytesPerSec>>24;
144     c[12] = wav->align;
145     c[13] = wav->align>>8;
146     c[14] = wav->bps;
147     c[15] = wav->bps>>8;
148     fwrite(c, 16, 1, fi);
149     fwrite(&b[16], 4, 1, fi);
150     c[0] = wav->size;
151     c[1] = wav->size>>8;
152     c[2] = wav->size>>16;
153     c[3] = wav->size>>24;
154     fwrite(c,4,1,fi);
155     printf("writing %d converted bytes\n", wav->size);
156     fwrite(wav->data,wav->size,1,fi);
157     fclose(fi);
158     return 1;
159 }
160
161 void printWAVInfo(struct WAV*wav)
162 {
163     printf("tag:%04x channels:%d samples/sec:%d bytes/sec:%d align:%d bits/sample:%d size:%d\n",
164             wav->tag, wav->channels, wav->sampsPerSec, wav->bytesPerSec, 
165             wav->align, wav->bps, wav->size);
166 }
167
168 int convertWAV2mono(struct WAV*src, struct WAV*dest, int rate)
169 {
170     int samplelen=src->size/src->align;
171     int bps=src->bps;
172     double ratio;
173     double pos = 0;
174     int pos2 = 0;
175     int channels=src->channels;
176     int i;
177     int fill;
178
179     dest->sampsPerSec = rate;
180     dest->bps = 16;
181     dest->channels = 1;
182     dest->align = 2;
183     dest->tag = src->tag;
184     dest->bytesPerSec = dest->sampsPerSec*dest->align;
185
186     ratio = (double)dest->sampsPerSec/(double)src->sampsPerSec;
187     fill = (int)(ratio+1)*2;
188     
189     dest->data = (unsigned char*)malloc((int)(samplelen*ratio*2)+128);
190     if(!dest->data) 
191         return 0;
192     dest->size = (int)(samplelen*ratio)*2;
193
194     if(bps == 8) {
195         if(ratio <= 1) {
196             for(i=0; i<src->size; i+=channels) {
197                 int pos2 = ((int)pos)*2;
198                 dest->data[pos2] = 0;
199                 dest->data[pos2+1] = src->data[i]+128;
200                 pos += ratio;
201             }
202         } else {
203             for(i=0; i<src->size; i+=channels) {
204                 int j;
205                 int pos2 = ((int)pos)*2;
206                 for(j=0;j<fill;j+=2) {
207                     dest->data[pos2+j+0] = 0;
208                     dest->data[pos2+j+1] = src->data[i]+128;
209                 }
210                 pos += ratio;
211             }
212         }
213     } else if(bps == 16) {
214         if(ratio <= 1) {
215             for(i=0; i<src->size/2; i+=channels) {
216                 int pos2 = ((int)pos)*2;
217                 dest->data[pos2+0]=src->data[i*2];
218                 dest->data[pos2+1]=src->data[i*2+1];
219                 pos += ratio;
220             }
221         } else {
222             for(i=0; i<src->size/2; i+=channels) {
223                 int j;
224                 int pos2 = ((int)pos)*2;
225                 for(j=0;j<fill;j+=2) {
226                     dest->data[pos2+j+0] = src->data[i*2];
227                     dest->data[pos2+j+1] = src->data[i*2+1];
228                 }
229                 pos += ratio;
230             }
231         }
232     } else if(bps == 32) {
233         if(ratio <= 1) {
234             for(i=0; i<src->size/4; i+=channels) {
235                 int pos2 = ((int)pos)*2;
236                 dest->data[pos2+0]=src->data[i*4+2];
237                 dest->data[pos2+1]=src->data[i*4+3];
238                 pos += ratio;
239             }
240         } else {
241             for(i=0; i<src->size/4; i+=channels) {
242                 int j;
243                 int pos2 = ((int)pos)*2;
244                 for(j=0;j<fill;j+=2) {
245                     dest->data[pos2+j+0] = src->data[i*4+2];
246                     dest->data[pos2+j+1] = src->data[i*4+3];
247                 }
248                 pos += ratio;
249             }
250         }
251     }
252     return 1;
253 }
254
255