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