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