ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/PDL-Audio/sndlib/sound.c
Revision: 1.1
Committed: Tue Dec 28 01:05:17 2004 UTC (19 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_1, rel-1_2, HEAD
Log Message:
*** empty log message ***

File Contents

# Content
1 /* sound.c */
2
3 /* TODO: make this thread-safe by wrapping locks around the header/data base references */
4
5 #if defined(HAVE_CONFIG_H)
6 #include "config.h"
7 #endif
8
9 #include <math.h>
10 #include <stdio.h>
11 #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_FCNTL_H))
12 #include <fcntl.h>
13 #endif
14 #include <signal.h>
15 #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_LIMITS_H))
16 #include <limits.h>
17 #endif
18 #include <errno.h>
19 #include <stdlib.h>
20
21 #if (defined(NEXT) || (defined(HAVE_LIBC_H) && (!defined(HAVE_UNISTD_H))))
22 #include <libc.h>
23 #else
24 #if (!(defined(_MSC_VER))) && (!(defined(MPW_C)))
25 #include <unistd.h>
26 #endif
27 #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_STRING_H))
28 #include <string.h>
29 #endif
30 #endif
31
32 #include <ctype.h>
33 #include <stddef.h>
34
35 #include "sndlib.h"
36
37 #if MACOS
38 #if (!defined(MPW_C))
39 #include <time.h>
40 #include <stat.h>
41 #endif
42 #else
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #endif
46
47 #include <stdarg.h>
48
49 static int mus_error_tag = MUS_INITIAL_ERROR_TAG;
50 int mus_make_error_tag(void) {return(mus_error_tag++);}
51 static void (*mus_error_handler)(int err_type, char *err_msg);
52 void mus_set_error_handler(void (*new_error_handler)(int err_type, char *err_msg)) {mus_error_handler = new_error_handler;}
53 static char *mus_error_buffer = NULL;
54
55 void mus_error(int error, char *format, ...)
56 {
57 va_list ap;
58 va_start(ap,format);
59 vsprintf(mus_error_buffer,format,ap);
60 va_end(ap);
61 if (mus_error_handler)
62 (*mus_error_handler)(error,mus_error_buffer);
63 else fprintf(stderr,mus_error_buffer);
64 }
65
66 void mus_fwrite(int fd, char *format, ...)
67 {
68 va_list ap;
69 va_start(ap,format);
70 vsprintf(mus_error_buffer,format,ap);
71 va_end(ap);
72 write(fd,mus_error_buffer,strlen(mus_error_buffer));
73 }
74
75 static char *s_copy_string (char *str)
76 {
77 char *newstr = NULL;
78 if ((str) && (*str))
79 {
80 newstr = (char *)CALLOC(strlen(str)+1,sizeof(char));
81 strcpy(newstr,str);
82 }
83 return(newstr);
84 }
85
86
87 #ifndef MPW_C
88 static time_t file_write_date(char *filename)
89 {
90 struct stat statbuf;
91 int err;
92 err = stat(filename,&statbuf);
93 if (err < 0) return(err);
94 return((time_t)(statbuf.st_mtime));
95 }
96 #else
97 #include <Files.h>
98 static int file_write_date(char *filename)
99 {
100 #if 0
101 /* this isn't right... */
102 HParamBlockRec pb;
103 FSSpec fs;
104 FSMakeFSSpec(0,0,(unsigned char *)filename,&fs);
105 pb.fileParam.ioVRefNum = fs.vRefNum;
106 pb.fileParam.ioDirID = fs.parID;
107 pb.fileParam.ioNamePtr = fs.name;
108 PBHGetFInfo(&pb,FALSE);
109 mus_error(0,"%s date: %d ",filename,pb.fileParam.ioFlMdDat);
110 return(pb.fileParam.ioFlMdDat);
111 #else
112 return(1);
113 #endif
114 }
115 #endif
116
117 static int sndlib_initialized = 0;
118
119 int initialize_sndlib(void)
120 {
121 int err = 0;
122 if (!sndlib_initialized)
123 {
124 sndlib_initialized = 1;
125 mus_error_buffer = (char *)CALLOC(256,sizeof(char));
126 if (mus_error_buffer == NULL) return(-1);
127 err = mus_create_header_buffer();
128 if (err == 0)
129 {
130 err = mus_create_descriptors();
131 if (err == 0) err = initialize_audio();
132 }
133 if (err == -1) {FREE(mus_error_buffer); return(-1);}
134 }
135 return(0);
136 }
137
138 typedef struct {
139 char *file_name; /* full path -- everything is keyed to this name */
140 int table_pos;
141 int *aux_comment_start,*aux_comment_end;
142 int *loop_modes,*loop_starts,*loop_ends;
143 int markers;
144 int *marker_ids,*marker_positions;
145 int samples, datum_size, data_location, srate, chans, header_type, data_format, original_sound_format, true_file_length;
146 int comment_start, comment_end, header_distributed, type_specifier, bits_per_sample, fact_samples, block_align;
147 int write_date;
148 int *max_amps;
149 } sound_file;
150
151 static int sound_table_size = 0;
152 static sound_file **sound_table = NULL;
153
154 static void free_sound_file(sound_file *sf)
155 {
156 if (sf)
157 {
158 sound_table[sf->table_pos] = NULL;
159 if (sf->aux_comment_start) FREE(sf->aux_comment_start);
160 if (sf->aux_comment_end) FREE(sf->aux_comment_end);
161 if (sf->file_name) FREE(sf->file_name);
162 if (sf->loop_modes) FREE(sf->loop_modes);
163 if (sf->loop_starts) FREE(sf->loop_starts);
164 if (sf->loop_ends) FREE(sf->loop_ends);
165 if (sf->marker_ids) FREE(sf->marker_ids);
166 if (sf->marker_positions) FREE(sf->marker_positions);
167 if (sf->max_amps) FREE(sf->max_amps);
168 FREE(sf);
169 }
170 }
171
172 static sound_file *add_to_sound_table(void)
173 {
174 int i,pos;
175 #ifdef MACOS
176 sound_file **ptr;
177 #endif
178 pos = -1;
179 for (i=0;i<sound_table_size;i++)
180 if (sound_table[i] == NULL)
181 {
182 pos = i;
183 break;
184 }
185 if (pos == -1)
186 {
187 pos = sound_table_size;
188 sound_table_size += 16;
189 if (sound_table == NULL)
190 sound_table = (sound_file **)CALLOC(sound_table_size,sizeof(sound_file *));
191 else
192 {
193 #ifdef MACOS
194 ptr = (sound_file **)CALLOC(sound_table_size,sizeof(sound_file *));
195 for (i=0;i<pos;i++) ptr[i] = sound_table[i];
196 FREE(sound_table);
197 sound_table = ptr;
198 #else
199 sound_table = (sound_file **)REALLOC(sound_table,sound_table_size * sizeof(sound_file *));
200 #endif
201 for (i=pos;i<sound_table_size;i++) sound_table[i] = NULL;
202 }
203 }
204 sound_table[pos] = (sound_file *)CALLOC(1,sizeof(sound_file));
205 sound_table[pos]->table_pos = pos;
206 return(sound_table[pos]);
207 }
208
209 static void re_read_raw_header(sound_file *sf)
210 {
211 int chan,data_size;
212 chan = mus_open_read(sf->file_name);
213 data_size = lseek(chan,0L,SEEK_END);
214 sf->true_file_length = data_size;
215 sf->samples = mus_bytes2samples(sf->data_format,data_size);
216 close(chan);
217 }
218
219 int forget_sound(char *name)
220 {
221 int i;
222 for (i=0;i<sound_table_size;i++)
223 {
224 if (sound_table[i])
225 {
226 if (strcmp(name,sound_table[i]->file_name) == 0)
227 {
228 free_sound_file(sound_table[i]);
229 return(0);
230 }
231 }
232 }
233 return(-1);
234 }
235
236 static sound_file *find_sound_file(char *name)
237 {
238 int i,date;
239 sound_file *sf;
240 for (i=0;i<sound_table_size;i++)
241 {
242 if (sound_table[i])
243 {
244 if (strcmp(name,sound_table[i]->file_name) == 0)
245 {
246 sf = sound_table[i];
247 date = file_write_date(name);
248 if (date == sf->write_date)
249 return(sf);
250 else
251 {
252 if (sf->header_type == raw_sound_file)
253 {
254 /* sound has changed since we last read it, but it has no header, so
255 * the only sensible thing to check is the new length (i.e. caller
256 * has set other fields by hand)
257 */
258 sf->write_date = date;
259 re_read_raw_header(sf);
260 return(sf);
261 }
262 free_sound_file(sf);
263 return(NULL);
264 }
265 }
266 }
267 }
268 return(NULL);
269 }
270
271 static void fill_sf_record(sound_file *sf)
272 {
273 sf->data_location = mus_header_data_location();
274 sf->samples = mus_header_samples();
275 sf->data_format = mus_header_format();
276 sf->srate = mus_header_srate();
277 sf->chans = mus_header_chans();
278 sf->datum_size = mus_header_format2bytes();
279 sf->header_type = mus_header_type();
280 sf->original_sound_format = mus_header_original_format();
281 sf->true_file_length = mus_true_file_length();
282 sf->comment_start = mus_header_comment_start();
283 sf->comment_end = mus_header_comment_end();
284 sf->header_distributed = mus_header_distributed();
285 sf->type_specifier = mus_header_type_specifier();
286 sf->bits_per_sample = mus_header_bits_per_sample();
287 sf->fact_samples = mus_header_fact_samples();
288 sf->block_align = mus_header_block_align();
289 sf->write_date = file_write_date(sf->file_name);
290 /* loop points and aux comments */
291 }
292
293 static sound_file *read_sound_file_header_with_fd(int fd, char *arg)
294 {
295 int err=0;
296 sound_file *sf = NULL;
297 initialize_sndlib();
298 err = mus_read_header_with_fd(fd);
299 if (err == -1) return(NULL);
300 sf = add_to_sound_table();
301 sf->file_name = s_copy_string(arg);
302 fill_sf_record(sf);
303 return(sf);
304 }
305
306 static sound_file *read_sound_file_header_with_name(char *name)
307 {
308 sound_file *sf = NULL;
309 initialize_sndlib();
310 if (mus_read_header(name) != -1)
311 {
312 sf = add_to_sound_table();
313 sf->file_name = s_copy_string(name);
314 fill_sf_record(sf);
315 }
316 return(sf);
317 }
318
319 static sound_file *getsf(char *arg)
320 {
321 sound_file *sf = NULL;
322 if ((sf = find_sound_file(arg)) == NULL)
323 {
324 sf = read_sound_file_header_with_name(arg);
325 if (sf == NULL) set_audio_error(SNDLIB_CANT_OPEN);
326 }
327 return(sf);
328 }
329
330 int sound_samples (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->samples); else return(-1);}
331 int sound_frames (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->samples / sf->chans); else return(-1);}
332 int sound_datum_size (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->datum_size); else return(-1);}
333 int sound_data_location (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->data_location); else return(-1);}
334 int sound_chans (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->chans); else return(-1);}
335 int sound_srate (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->srate); else return(-1);}
336 int sound_header_type (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->header_type); else return(-1);}
337 int sound_data_format (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->data_format); else return(-1);}
338 int sound_original_format (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->original_sound_format); else return(-1);}
339 int sound_comment_start (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->comment_start); else return(-1);}
340 int sound_comment_end (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->comment_end); else return(-1);}
341 int sound_length (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->true_file_length); else return(-1);}
342 int sound_fact_samples (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->fact_samples); else return(-1);}
343 int sound_distributed (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->header_distributed); else return(-1);}
344 int sound_write_date (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->write_date); else return(-1);}
345 int sound_type_specifier (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->type_specifier); else return(-1);}
346 int sound_align (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->block_align); else return(-1);}
347 int sound_bits_per_sample (char *arg) {sound_file *sf; sf = getsf(arg); if (sf) return(sf->bits_per_sample); else return(-1);}
348 float sound_duration(char *arg) {return((float)sound_frames(arg) / (float)sound_srate(arg));}
349
350 int sound_aiff_p(char *arg)
351 {
352 return(sound_header_type(arg) == AIFF_sound_file);
353 }
354
355 char *sound_comment(char *name)
356 {
357 int start,end,fd,len;
358 char *sc = NULL;
359 start = sound_comment_start(name);
360 end = sound_comment_end(name);
361 if (end == 0) return(NULL);
362 len = end-start+1;
363 if (len>0)
364 {
365 /* open and get the comment */
366 sc = (char *)CALLOC(len+1,sizeof(char)); /* len+1 calloc'd => we'll always have a trailing null */
367 #if MACOS
368 fd = open(name,O_RDONLY);
369 #else
370 #ifdef WINDOZE
371 fd = open(name,O_RDONLY | O_BINARY);
372 #else
373 fd = open(name,O_RDONLY,0);
374 #endif
375 #endif
376 lseek(fd,start,SEEK_SET);
377 read(fd,sc,len);
378 close(fd);
379 return(sc);
380 }
381 else return(NULL);
382 }
383
384 char *sound_type_name(int type)
385 {
386 return(mus_header_type2string(type));
387 }
388
389 char *sound_format_name(int format)
390 {
391 return(mus_header_data_format2string(format));
392 }
393
394 int sound_bytes_per_sample(int format) {return(mus_format2bytes(format));}
395
396 typedef struct {
397 int fd;
398 char *name;
399 } output_info;
400
401 static output_info **header_names = NULL;
402 static int header_names_size = 0;
403
404 static void save_header_name(int fd, char *arg)
405 {
406 int i,loc;
407 #ifdef MACOS
408 output_info **ptr;
409 #endif
410 loc = -1;
411 for (i=0;i<header_names_size;i++)
412 {
413 if (header_names[i] == NULL)
414 {
415 loc = i;
416 break;
417 }
418 }
419 if (loc == -1)
420 {
421 loc = header_names_size;
422 header_names_size += 4;
423 if (header_names == NULL)
424 header_names = (output_info **)CALLOC(header_names_size,sizeof(output_info *));
425 else
426 {
427 #ifdef MACOS
428 ptr = (output_info **)CALLOC(header_names_size,sizeof(output_info *));
429 for (i=0;i<loc;i++) ptr[i] = header_names[i];
430 FREE(header_names);
431 header_names = ptr;
432 #else
433 header_names = (output_info **)REALLOC(header_names,header_names_size * sizeof(output_info *));
434 #endif
435 for (i=loc;i<header_names_size;i++) header_names[i] = NULL;
436 }
437 }
438 header_names[loc] = (output_info *)CALLOC(1,sizeof(output_info));
439 header_names[loc]->fd = fd;
440 header_names[loc]->name = s_copy_string(arg);
441 }
442
443 static void flush_header(int fd)
444 {
445 int i,loc,val;
446 sound_file *sf;
447 loc = -1;
448 val = -1;
449 for (i=0;i<header_names_size;i++)
450 {
451 if (header_names[i])
452 {
453 if (header_names[i]->fd == fd)
454 {
455 loc = i;
456 break;
457 }
458 }
459 }
460 if (loc != -1)
461 {
462 if (header_names[loc]->name)
463 {
464 sf = getsf(header_names[loc]->name);
465 if (sf) sf->write_date = 0; /* force subsequent re-read */
466 FREE(header_names[loc]->name);
467 header_names[loc]->name = NULL;
468 }
469 FREE(header_names[loc]);
470 header_names[loc] = NULL;
471 }
472 }
473
474 int open_sound_input (char *arg)
475 {
476 int fd;
477 sound_file *sf = NULL;
478 set_audio_error(SNDLIB_NO_ERROR);
479 initialize_sndlib();
480 fd = mus_open_read(arg);
481 if (fd != -1)
482 {
483 if ((sf = find_sound_file(arg)) == NULL)
484 {
485 sf = read_sound_file_header_with_fd(fd,arg);
486 }
487 }
488 if (sf)
489 {
490 mus_set_file_descriptors(fd,sf->data_format,sf->datum_size,sf->data_location,sf->chans,sf->header_type);
491 mus_seek(fd,sf->data_location,SEEK_SET);
492 }
493 else set_audio_error(SNDLIB_CANT_OPEN);
494 return(fd);
495 }
496
497 int open_sound_output (char *arg, int srate, int chans, int data_format, int header_type, char *comment)
498 {
499 int fd = 0,err,comlen = 0;
500 if (comment) comlen = strlen(comment);
501 set_audio_error(SNDLIB_NO_ERROR);
502 initialize_sndlib();
503 err = mus_write_header(arg,header_type,srate,chans,0,0,data_format,comment,comlen);
504 if (err != -1)
505 {
506 fd = mus_open_write(arg);
507 mus_set_file_descriptors(fd,data_format,mus_format2bytes(data_format),mus_header_data_location(),chans,header_type);
508 save_header_name(fd,arg);
509 }
510 else set_audio_error(SNDLIB_CANT_OPEN);
511 return(fd);
512 }
513
514 int reopen_sound_output(char *arg, int chans, int format, int type, int data_loc)
515 {
516 int fd;
517 set_audio_error(SNDLIB_NO_ERROR);
518 initialize_sndlib();
519 fd = mus_reopen_write(arg);
520 mus_set_file_descriptors(fd,format,mus_format2bytes(format),data_loc,chans,type);
521 save_header_name(fd,arg);
522 return(fd);
523 }
524
525 int close_sound_input (int fd)
526 {
527 return(mus_close(fd)); /* this closes the clm file descriptors */
528 }
529
530 int close_sound_output (int fd, int bytes_of_data)
531 {
532 flush_header(fd);
533 mus_update_header_with_fd(fd,mus_get_header_type(fd),bytes_of_data);
534 return(mus_close(fd));
535 }
536
537 int read_sound (int fd, int beg, int end, int chans, int **bufs)
538 {
539 return(mus_read(fd,beg,end,chans,bufs));
540 }
541
542 int write_sound (int tfd, int beg, int end, int chans, int **bufs)
543 {
544 return(mus_write(tfd,beg,end,chans,bufs));
545 }
546
547 int seek_sound (int tfd, long offset, int origin)
548 {
549 return(mus_seek(tfd,offset,origin));
550 }
551
552 int seek_sound_frame(int tfd, int frame)
553 {
554 return(mus_seek_frame(tfd,frame));
555 }
556
557 int override_sound_header(char *arg, int srate, int chans, int format, int type, int location, int size)
558 {
559 sound_file *sf;
560 /* perhaps once a header has been over-ridden, we should not reset the relevant fields upon re-read? */
561 sf = getsf(arg);
562 if (sf)
563 {
564 if (location != -1) sf->data_location = location;
565 if (size != -1) sf->samples = size;
566 if (format != -1)
567 {
568 sf->data_format = format;
569 sf->datum_size = mus_format2bytes(format);
570 }
571 if (srate != -1) sf->srate = srate;
572 if (chans != -1) sf->chans = chans;
573 if (type != -1) sf->header_type = type;
574 return(0);
575 }
576 else return(-1);
577 }
578
579 int sound_max_amp(char *ifile, int *vals)
580 {
581 int ifd,ichans,bufnum,n,curframes,i,frames,chn,fc;
582 int *buffer,*time,*samp;
583 int **ibufs;
584 sound_file *sf;
585 sf = getsf(ifile);
586 if ((sf) && (sf->max_amps))
587 {
588 for (chn=0;chn<sf->chans;chn++)
589 {
590 vals[chn*2] = sf->max_amps[chn*2];
591 vals[chn*2+1] = sf->max_amps[chn*2+1];
592 }
593 return(sf->samples / sf->chans);
594 }
595 ifd = open_sound_input(ifile);
596 sf = getsf(ifile);
597 if (ifd == -1) return(-1);
598 ichans = sound_chans(ifile);
599 frames = sound_frames(ifile);
600 if (frames <= 0) {close_sound_input(ifd); return(0);}
601 seek_sound_frame(ifd,0);
602 ibufs = (int **)CALLOC(ichans,sizeof(int *));
603 bufnum = 8192;
604 for (i=0;i<ichans;i++) ibufs[i] = (int *)CALLOC(bufnum,sizeof(int));
605 time = (int *)CALLOC(ichans,sizeof(int));
606 samp = (int *)CALLOC(ichans,sizeof(int));
607 for (n=0;n<frames;n+=bufnum)
608 {
609 if ((n+bufnum)<frames) curframes = bufnum; else curframes = (frames-n);
610 read_sound(ifd,0,curframes-1,ichans,ibufs);
611 for (chn=0;chn<ichans;chn++)
612 {
613 buffer = (int *)(ibufs[chn]);
614 fc=samp[chn];
615 for (i=0;i<curframes;i++)
616 {
617 if ((buffer[i]>fc) || (fc < -buffer[i]))
618 {
619 time[chn]=i+n;
620 samp[chn]=buffer[i];
621 if (samp[chn]<0) samp[chn] = -samp[chn];
622 fc = samp[chn];
623 }
624 }
625 }
626 }
627 close_sound_input(ifd);
628 if (sf->max_amps == NULL) sf->max_amps = (int *)CALLOC(ichans*2,sizeof(int));
629 for (chn=0,i=0;chn<ichans;chn++,i+=2)
630 {
631 vals[i]=samp[chn];
632 vals[i+1]=time[chn];
633 sf->max_amps[i] = vals[i];
634 sf->max_amps[i+1] = vals[i+1];
635 }
636 FREE(time);
637 FREE(samp);
638 for (i=0;i<ichans;i++) FREE(ibufs[i]);
639 FREE(ibufs);
640 return(frames);
641 }
642
643
644 int mus_file2array(char *filename, int chan, int start, int samples, int *array)
645 {
646 int ifd,chans,total_read;
647 int **bufs;
648 ifd = open_sound_input(filename);
649 if (ifd == -1) return(-1);
650 chans = sound_chans(filename);
651 bufs = (int **)CALLOC(chans,sizeof(int *));
652 bufs[chan] = array;
653 seek_sound_frame(ifd,start);
654 total_read = mus_read_any(ifd,0,chans,samples,bufs,(int *)bufs);
655 close_sound_input(ifd);
656 FREE(bufs);
657 return(total_read);
658 }
659
660 int mus_array2file(char *filename, int *ddata, int len, int srate, int channels)
661 {
662 /* put ddata into a sound file, taking byte order into account */
663 /* assume ddata is interleaved already if more than one channel */
664 int fd;
665 #ifdef SNDLIB_LITTLE_ENDIAN
666 int i;
667 unsigned char *o;
668 unsigned char tmp;
669 #endif
670 fd = mus_create(filename);
671 if (fd == -1) return(-1);
672 mus_write_next_header(fd,srate,channels,28,len*4,SNDLIB_32_LINEAR,NULL,0);
673 #ifdef SNDLIB_LITTLE_ENDIAN
674 o = (unsigned char *)ddata;
675 for (i=0;i<len;i++,o+=4)
676 {
677 tmp = o[0]; o[0]=o[3]; o[3]=tmp; tmp=o[1]; o[1]=o[2]; o[2]=tmp;
678 }
679 #endif
680 #ifndef MACOS
681 write(fd,(unsigned char *)ddata,len*4);
682 #else
683 write(fd,(char *)ddata,len*4);
684 #endif
685 close(fd);
686 return(0);
687 }
688