1 /*************************************************************************/
2 /*                                                                       */
3 /*                  Language Technologies Institute                      */
4 /*                     Carnegie Mellon University                        */
5 /*                         Copyright (c) 2000                            */
6 /*                        All Rights Reserved.                           */
7 /*                                                                       */
8 /*  Permission is hereby granted, free of charge, to use and distribute  */
9 /*  this software and its documentation without restriction, including   */
10 /*  without limitation the rights to use, copy, modify, merge, publish,  */
11 /*  distribute, sublicense, and/or sell copies of this work, and to      */
12 /*  permit persons to whom this work is furnished to do so, subject to   */
13 /*  the following conditions:                                            */
14 /*   1. The code must retain the above copyright notice, this list of    */
15 /*      conditions and the following disclaimer.                         */
16 /*   2. Any modifications must be clearly marked as such.                */
17 /*   3. Original authors' names are not deleted.                         */
18 /*   4. The authors' names are not used to endorse or promote products   */
19 /*      derived from this software without specific prior written        */
20 /*      permission.                                                      */
21 /*                                                                       */
22 /*  CARNEGIE MELLON UNIVERSITY AND THE CONTRIBUTORS TO THIS WORK         */
23 /*  DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING      */
24 /*  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT   */
25 /*  SHALL CARNEGIE MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE      */
26 /*  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    */
27 /*  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN   */
28 /*  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,          */
29 /*  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF       */
30 /*  THIS SOFTWARE.                                                       */
31 /*                                                                       */
32 /*************************************************************************/
33 /*             Author:  Alan W Black (awb@cs.cmu.edu)                    */
34 /*               Date:  August 2000                                      */
35 /*************************************************************************/
36 /*                                                                       */
37 /*  Waveforms                                                            */
38 /*                                                                       */
39 /*************************************************************************/
40 #include "cst_string.h"
41 #include "cst_wave.h"
42 #include "cst_file.h"
43 
cst_wave_resample(cst_wave * w,int sample_rate)44 void cst_wave_resample(cst_wave *w, int sample_rate)
45 {
46     /* This is here so that it won't necessarily be linked in tight-space */
47     /* platforms like PalmOS                                              */
48 
49     cst_rateconv *filt;
50     int up, down;
51     short *in;
52     const short *inptr;
53     short *outptr;
54     int n, insize, outsize;
55 
56     /* Sure, we could take the GCD.  In practice, though, this
57        gives us what we want and makes things go faster. */
58     down = w->sample_rate / 1000;
59     up = sample_rate / 1000;
60 
61     if (up < 1 || down < 1) {
62 	cst_errmsg("cst_wave_resample: invalid input/output sample rates (%d, %d)\n",
63 		   up * 1000, down * 1000);
64 	cst_error();
65     }
66 
67     filt = new_rateconv(up, down, w->num_channels);
68 
69     inptr = in = w->samples;
70     insize = w->num_samples;
71 
72     w->num_samples = w->num_samples * up / down + 2048;
73     w->samples = cst_alloc(short, w->num_samples * w->num_channels);
74     w->sample_rate = sample_rate;
75 
76     outptr = w->samples;
77     outsize = w->num_samples;
78 
79     while ((n = cst_rateconv_in(filt, inptr, insize)) > 0) {
80 	inptr += n;
81 	insize -= n;
82 
83 	while ((n = cst_rateconv_out(filt, outptr, outsize)) > 0) {
84 	    outptr += n;
85 	    outsize -= n;
86 	}
87     }
88     cst_rateconv_leadout(filt);
89     while ((n = cst_rateconv_out(filt, outptr, outsize)) > 0) {
90 	outptr += n;
91 	outsize -= n;
92     }
93 
94     cst_free(in);
95     delete_rateconv(filt);
96 
97 }
98 
cst_wave_save(cst_wave * w,const char * filename,const char * type)99 int cst_wave_save(cst_wave *w,const char *filename,const char *type)
100 {
101     if (cst_streq(type,"riff"))
102 	return cst_wave_save_riff(w,filename);
103 /*    else if (cst_streq(type,"aiff"))
104 	return cst_wave_save_aiff(w,filename);
105     else if (cst_streq(type,"snd"))
106     return cst_wave_save_snd(w,filename); */
107     else if (cst_streq(type,"raw"))
108 	return cst_wave_save_raw(w,filename);
109     else
110     {
111 	cst_errmsg("cst_wave_save: unsupported wavetype \"%s\"\n",
112 		   type);
113 	return -1;
114     }
115 }
116 
cst_wave_save_raw(cst_wave * w,const char * filename)117 int cst_wave_save_raw(cst_wave *w, const char *filename)
118 {
119     cst_file fd;
120     int rv;
121 
122     if ((fd = cst_fopen(filename,CST_OPEN_WRITE|CST_OPEN_BINARY)) == NULL)
123     {
124 	cst_errmsg("cst_wave_save: can't open file \"%s\"\n",
125 		   filename);
126 	return -1;
127     }
128 
129     rv = cst_wave_save_raw_fd(w, fd);
130     cst_fclose(fd);
131 
132     return rv;
133 }
134 
cst_wave_save_raw_fd(cst_wave * w,cst_file fd)135 int cst_wave_save_raw_fd(cst_wave *w, cst_file fd)
136 {
137     if (cst_fwrite(fd, cst_wave_samples(w),
138 		   sizeof(short), cst_wave_num_samples(w)) == cst_wave_num_samples(w))
139 	return 0;
140     else
141 	return -1;
142 }
143 
144 
cst_wave_append_riff(cst_wave * w,const char * filename)145 int cst_wave_append_riff(cst_wave *w,const char *filename)
146 {
147     /* Appends to wave in file if it already exists */
148     cst_file fd;
149     cst_wave_header hdr;
150     char info[4];
151     int d_int;
152     int rv, num_bytes, n, sample_rate;
153 
154     if ((fd = cst_fopen(filename,CST_OPEN_WRITE|CST_OPEN_READ|CST_OPEN_BINARY)) == NULL)
155     {
156 	cst_errmsg("cst_wave_append: can't open file \"%s\"\n",
157 		   filename);
158 	return -1;
159     }
160 
161     rv = cst_wave_load_riff_header(&hdr,fd);
162     if (rv != CST_OK_FORMAT)
163     {
164 	cst_fclose(fd);
165 	return rv;
166     }
167     /* We will assume this is one of my riff files so it has *ONE* data part */
168     cst_fread(fd,info,1,4);
169     cst_fread(fd,&d_int,4,1);
170     if (CST_BIG_ENDIAN) d_int = SWAPINT(d_int);
171     hdr.num_samples = d_int/sizeof(short);
172 
173     cst_fseek(fd,
174 	      cst_ftell(fd)+(hdr.hsize-16)+
175 	      (hdr.num_samples*hdr.num_channels*sizeof(short)),
176 	      CST_SEEK_ABSOLUTE);
177 
178     if (CST_BIG_ENDIAN)
179     {
180 	short *xdata = cst_alloc(short,cst_wave_num_channels(w)*
181 				 cst_wave_num_samples(w));
182 	memmove(xdata,cst_wave_samples(w),
183 		sizeof(short)*cst_wave_num_channels(w)*
184 		cst_wave_num_samples(w));
185 	swap_bytes_short(xdata,
186 			 cst_wave_num_channels(w)*
187 			 cst_wave_num_samples(w));
188 	n = cst_fwrite(fd,xdata,sizeof(short),
189 		       cst_wave_num_channels(w)*cst_wave_num_samples(w));
190 	cst_free(xdata);
191     }
192     else
193     {
194 	n = cst_fwrite(fd,cst_wave_samples(w),sizeof(short),
195 		       cst_wave_num_channels(w)*cst_wave_num_samples(w));
196     }
197 
198     cst_fseek(fd,4,CST_SEEK_ABSOLUTE);
199     num_bytes = hdr.num_bytes + (n*sizeof(short));
200     if (CST_BIG_ENDIAN) num_bytes = SWAPINT(num_bytes);
201     cst_fwrite(fd,&num_bytes,4,1); /* num bytes in whole file */
202     cst_fseek(fd,4+4+4+4 +4+2+2 ,CST_SEEK_ABSOLUTE);
203     sample_rate = w->sample_rate;
204     if (CST_BIG_ENDIAN) sample_rate = SWAPINT(sample_rate);
205     cst_fwrite(fd,&sample_rate,4,1); /* sample rate */
206     cst_fseek(fd,4+4+4+4+4+2+2+4+4+2+2+4,CST_SEEK_ABSOLUTE);
207     num_bytes =
208 	(sizeof(short) * cst_wave_num_channels(w) * cst_wave_num_samples(w)) +
209 	(sizeof(short) * hdr.num_channels * hdr.num_samples);
210     if (CST_BIG_ENDIAN) num_bytes = SWAPINT(num_bytes);
211     cst_fwrite(fd,&num_bytes,4,1); /* num bytes in data */
212     cst_fclose(fd);
213 
214     return rv;
215 }
216 
cst_wave_save_riff(cst_wave * w,const char * filename)217 int cst_wave_save_riff(cst_wave *w,const char *filename)
218 {
219     cst_file fd;
220     int rv;
221 
222     if ((fd = cst_fopen(filename,CST_OPEN_WRITE|CST_OPEN_BINARY)) == NULL)
223     {
224 	cst_errmsg("cst_wave_save: can't open file \"%s\"\n",
225 		   filename);
226 	return -1;
227     }
228 
229     rv = cst_wave_save_riff_fd(w, fd);
230     cst_fclose(fd);
231 
232     return rv;
233 }
234 
cst_wave_save_riff_fd(cst_wave * w,cst_file fd)235 int cst_wave_save_riff_fd(cst_wave *w, cst_file fd)
236 {
237     const char *info;
238     short d_short;
239     int d_int, n;
240     int num_bytes;
241 
242     info = "RIFF";
243     cst_fwrite(fd,info,4,1);
244     num_bytes = (cst_wave_num_samples(w)
245 		 * cst_wave_num_channels(w)
246 		 * sizeof(short)) + 8 + 16 + 12;
247     if (CST_BIG_ENDIAN) num_bytes = SWAPINT(num_bytes);
248     cst_fwrite(fd,&num_bytes,4,1); /* num bytes in whole file */
249     info = "WAVE";
250     cst_fwrite(fd,info,1,4);
251     info = "fmt ";
252     cst_fwrite(fd,info,1,4);
253     num_bytes = 16;                   /* size of header */
254     if (CST_BIG_ENDIAN) num_bytes = SWAPINT(num_bytes);
255     cst_fwrite(fd,&num_bytes,4,1);
256     d_short = RIFF_FORMAT_PCM;        /* sample type */
257     if (CST_BIG_ENDIAN) d_short = SWAPSHORT(d_short);
258     cst_fwrite(fd,&d_short,2,1);
259     d_short = cst_wave_num_channels(w); /* number of channels */
260     if (CST_BIG_ENDIAN) d_short = SWAPSHORT(d_short);
261     cst_fwrite(fd,&d_short,2,1);
262     d_int = cst_wave_sample_rate(w);  /* sample rate */
263     if (CST_BIG_ENDIAN) d_int = SWAPINT(d_int);
264     cst_fwrite(fd,&d_int,4,1);
265     d_int = (cst_wave_sample_rate(w)
266 	     * cst_wave_num_channels(w)
267 	     * sizeof(short));        /* average bytes per second */
268     if (CST_BIG_ENDIAN) d_int = SWAPINT(d_int);
269     cst_fwrite(fd,&d_int,4,1);
270     d_short = (cst_wave_num_channels(w)
271 	       * sizeof(short));      /* block align */
272     if (CST_BIG_ENDIAN) d_short = SWAPSHORT(d_short);
273     cst_fwrite(fd,&d_short,2,1);
274     d_short = 2 * 8;                  /* bits per sample */
275     if (CST_BIG_ENDIAN) d_short = SWAPSHORT(d_short);
276     cst_fwrite(fd,&d_short,2,1);
277     info = "data";
278     cst_fwrite(fd,info,1,4);
279     d_int = (cst_wave_num_channels(w)
280 	     * cst_wave_num_samples(w)
281 	     * sizeof(short));	      /* bytes in data */
282     if (CST_BIG_ENDIAN) d_int = SWAPINT(d_int);
283     cst_fwrite(fd,&d_int,4,1);
284 
285     if (CST_BIG_ENDIAN)
286     {
287         short *xdata = cst_alloc(short,cst_wave_num_channels(w)*
288 				 cst_wave_num_samples(w));
289 	memmove(xdata,cst_wave_samples(w),
290 		sizeof(short)*cst_wave_num_channels(w)*
291 		cst_wave_num_samples(w));
292 	swap_bytes_short(xdata,
293 			 cst_wave_num_channels(w)*
294 			 cst_wave_num_samples(w));
295 	n = cst_fwrite(fd,xdata,sizeof(short),
296 		       cst_wave_num_channels(w)*cst_wave_num_samples(w));
297 	cst_free(xdata);
298     }
299     else
300     {
301 	n = cst_fwrite(fd,cst_wave_samples(w),sizeof(short),
302 		       cst_wave_num_channels(w)*cst_wave_num_samples(w));
303     }
304 
305     if (n != cst_wave_num_channels(w)*cst_wave_num_samples(w))
306 	return -1;
307     else
308 	return 0;
309 
310 }
311 
cst_wave_load_raw(cst_wave * w,const char * filename,const char * bo,int sample_rate)312 int cst_wave_load_raw(cst_wave *w,const char *filename,
313 		      const char *bo, int sample_rate)
314 {
315     cst_file fd;
316     int r;
317 
318     if ((fd = cst_fopen(filename,CST_OPEN_READ|CST_OPEN_BINARY)) == NULL)
319     {
320 	cst_errmsg("cst_wave_load: can't open file \"%s\"\n",
321 		   filename);
322 	return -1;
323     }
324 
325     r = cst_wave_load_raw_fd(w, fd, bo, sample_rate);
326 
327     cst_fclose(fd);
328 
329     return r;
330 }
331 
cst_wave_load_raw_fd(cst_wave * w,cst_file fd,const char * bo,int sample_rate)332 int cst_wave_load_raw_fd(cst_wave *w, cst_file fd,
333 			 const char *bo, int sample_rate)
334 {
335     long size;
336 
337     /* Won't work on pipes, tough luck... */
338     size = cst_filesize(fd) / sizeof(short);
339     cst_wave_resize(w, size, 1);
340     if (cst_fread(fd, w->samples, sizeof(short), size) != size)
341 	return -1;
342 
343     w->sample_rate = sample_rate;
344     if (bo) /* if it's NULL we don't care */
345 	if ((CST_LITTLE_ENDIAN && cst_streq(bo, BYTE_ORDER_BIG))
346 	    || (CST_BIG_ENDIAN && cst_streq(bo, BYTE_ORDER_LITTLE)))
347 	    swap_bytes_short(w->samples,w->num_samples);
348 
349     return 0;
350 }
351 
cst_wave_load_riff(cst_wave * w,const char * filename)352 int cst_wave_load_riff(cst_wave *w,const char *filename)
353 {
354     cst_file fd;
355     int r;
356 
357     if ((fd = cst_fopen(filename,CST_OPEN_READ|CST_OPEN_BINARY)) == NULL)
358     {
359 	cst_errmsg("cst_wave_load: can't open file \"%s\"\n",
360 		   filename);
361 	return -1;
362     }
363 
364     r = cst_wave_load_riff_fd(w,fd);
365 
366     cst_fclose(fd);
367 
368     return r;
369 }
370 
cst_wave_load_riff_header(cst_wave_header * header,cst_file fd)371 int cst_wave_load_riff_header(cst_wave_header *header,cst_file fd)
372 {
373     char info[4];
374     short d_short;
375     int d_int;
376 
377     if (cst_fread(fd,info,1,4) != 4)
378 	return CST_WRONG_FORMAT;
379     else if (strncmp(info,"RIFF",4) != 0)
380 	return CST_WRONG_FORMAT;
381 
382     cst_fread(fd,&d_int,4,1);
383     if (CST_BIG_ENDIAN) d_int = SWAPINT(d_int);
384     header->num_bytes = d_int;
385 
386     if ((cst_fread(fd,info,1,4) != 4) ||
387 	(strncmp(info,"WAVE",4) != 0))
388 	return CST_ERROR_FORMAT;
389 
390     if ((cst_fread(fd,info,1,4) != 4) ||
391 	(strncmp(info,"fmt ",4) != 0))
392 	return CST_ERROR_FORMAT;
393 
394     cst_fread(fd,&d_int,4,1);
395     if (CST_BIG_ENDIAN) d_int = SWAPINT(d_int);
396     header->hsize = d_int;
397     cst_fread(fd,&d_short,2,1);
398     if (CST_BIG_ENDIAN) d_short = SWAPSHORT(d_short);
399 
400     if (d_short != RIFF_FORMAT_PCM)
401     {
402 	cst_errmsg("cst_load_wave_riff: unsupported sample format\n");
403 	return CST_ERROR_FORMAT;
404     }
405     cst_fread(fd,&d_short,2,1);
406     if (CST_BIG_ENDIAN) d_short = SWAPSHORT(d_short);
407 
408     header->num_channels = d_short;
409 
410     cst_fread(fd,&d_int,4,1);
411     if (CST_BIG_ENDIAN) d_int = SWAPINT(d_int);
412     header->sample_rate = d_int;
413     cst_fread(fd,&d_int,4,1);              /* avg bytes per second */
414     cst_fread(fd,&d_short,2,1);            /* block align */
415     cst_fread(fd,&d_short,2,1);            /* bits per sample */
416 
417     return CST_OK_FORMAT;
418 }
419 
cst_wave_load_riff_fd(cst_wave * w,cst_file fd)420 int cst_wave_load_riff_fd(cst_wave *w,cst_file fd)
421 {
422     cst_wave_header hdr;
423     int rv;
424     char info[4];
425     int d_int, d;
426     int data_length;
427     int samples;
428 
429     rv = cst_wave_load_riff_header(&hdr,fd);
430     if (rv != CST_OK_FORMAT)
431 	return rv;
432 
433     cst_fseek(fd,cst_ftell(fd)+(hdr.hsize-16),CST_SEEK_ABSOLUTE); /* skip rest of header */
434 
435     /* Note there's a bunch of potential random headers */
436     while (1)
437     {
438 	if (cst_fread(fd,info,1,4) != 4)
439 	    return CST_ERROR_FORMAT;
440 	if (strncmp(info,"data",4) == 0)
441 	{
442 	    cst_fread(fd,&d_int,4,1);
443 	    if (CST_BIG_ENDIAN) d_int = SWAPINT(d_int);
444 	    samples = d_int/sizeof(short);
445 	    break;
446 	}
447 	else if (strncmp(info,"fact",4) == 0)
448 	{
449 	    cst_fread(fd,&d_int,4,1);
450 	    if (CST_BIG_ENDIAN) d_int = SWAPINT(d_int);
451 	    cst_fseek(fd,cst_ftell(fd)+d_int,CST_SEEK_ABSOLUTE);
452 	}
453 	else if (strncmp(info,"clm ",4) == 0)
454 	{   /* another random chunk type -- resample puts this one in */
455 	    cst_fread(fd,&d_int,4,1);
456 	    if (CST_BIG_ENDIAN) d_int = SWAPINT(d_int);
457 	    cst_fseek(fd,cst_ftell(fd)+d_int,CST_SEEK_ABSOLUTE);
458 	}
459 	else
460 	{
461 	    cst_errmsg("cst_wave_load_riff: unsupported chunk type \"%*s\"\n",
462 		       4,info);
463 	    return CST_ERROR_FORMAT;
464 	}
465     }
466 
467     /* Now read the data itself */
468     cst_wave_set_sample_rate(w,hdr.sample_rate);     /* sample rate */
469     data_length = samples;
470     cst_wave_resize(w,samples/hdr.num_channels,hdr.num_channels);
471 
472     if ((d = cst_fread(fd,w->samples,sizeof(short),data_length)) != data_length)
473     {
474 	cst_errmsg("cst_wave_load_riff: %d missing samples, resized accordingly\n",
475 		   data_length-d);
476 	w->num_samples = d;
477     }
478 
479     if (CST_BIG_ENDIAN)
480 	swap_bytes_short(w->samples,w->num_samples);
481 
482     return CST_OK_FORMAT;
483 }
484