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