1 #include "mus-config.h"
2
3 #if USE_SND
4 #include "snd.h"
5 #endif
6
7 #include <math.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <stddef.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <time.h>
15 #include <stdarg.h>
16
17 #ifndef _MSC_VER
18 #include <unistd.h>
19 #else
20 #include <io.h>
21 #pragma warning(disable: 4244)
22 #endif
23 #include <string.h>
24
25 #include "_sndlib.h"
26 #include "sndlib-strings.h"
27
28
29 static mus_error_handler_t *mus_error_handler = NULL;
30
mus_error_set_handler(mus_error_handler_t * new_error_handler)31 mus_error_handler_t *mus_error_set_handler(mus_error_handler_t *new_error_handler)
32 {
33 mus_error_handler_t *old_handler;
34 old_handler = mus_error_handler;
35 mus_error_handler = new_error_handler;
36 return(old_handler);
37 }
38
39
40 static char *mus_error_buffer = NULL;
41 static int mus_error_buffer_size = 1024;
42
mus_error(int error,const char * format,...)43 int mus_error(int error, const char *format, ...)
44 {
45 int bytes_needed = 0;
46 va_list ap;
47
48 if (!format)
49 return(MUS_ERROR); /* else bus error in Mac OSX */
50
51 if (!mus_error_buffer)
52 mus_error_buffer = (char *)calloc(mus_error_buffer_size, sizeof(char));
53
54 va_start(ap, format);
55
56 /* can't use vasprintf here or below because the error handler may jump anywhere,
57 * leaving unfreed memory behind.
58 */
59 bytes_needed = vsnprintf(mus_error_buffer, mus_error_buffer_size, format, ap);
60 va_end(ap);
61
62 if (bytes_needed >= mus_error_buffer_size)
63 {
64 mus_error_buffer_size = bytes_needed * 2;
65 free(mus_error_buffer);
66 mus_error_buffer = (char *)calloc(mus_error_buffer_size, sizeof(char));
67
68 va_start(ap, format);
69 vsnprintf(mus_error_buffer, mus_error_buffer_size, format, ap);
70 va_end(ap);
71 }
72
73 if (mus_error_handler)
74 (*mus_error_handler)(error, mus_error_buffer);
75 else
76 {
77 fprintf(stderr, "%s", mus_error_buffer);
78 fputc('\n', stderr);
79 }
80
81 return(MUS_ERROR);
82 }
83
84
85 static mus_print_handler_t *mus_print_handler = NULL;
86
mus_print_set_handler(mus_print_handler_t * new_print_handler)87 mus_print_handler_t *mus_print_set_handler(mus_print_handler_t *new_print_handler)
88 {
89 mus_print_handler_t *old_handler;
90 old_handler = mus_print_handler;
91 mus_print_handler = new_print_handler;
92 return(old_handler);
93 }
94
95
mus_print(const char * format,...)96 void mus_print(const char *format, ...)
97 {
98 va_list ap;
99
100 if (mus_print_handler)
101 {
102 int bytes_needed = 0;
103
104 if (!mus_error_buffer)
105 mus_error_buffer = (char *)calloc(mus_error_buffer_size, sizeof(char));
106
107 va_start(ap, format);
108 bytes_needed = vsnprintf(mus_error_buffer, mus_error_buffer_size, format, ap);
109 va_end(ap);
110
111 if (bytes_needed >= mus_error_buffer_size)
112 {
113 mus_error_buffer_size = bytes_needed * 2;
114 free(mus_error_buffer);
115 mus_error_buffer = (char *)calloc(mus_error_buffer_size, sizeof(char));
116
117 va_start(ap, format);
118 vsnprintf(mus_error_buffer, mus_error_buffer_size, format, ap);
119 va_end(ap);
120 }
121
122 (*mus_print_handler)(mus_error_buffer);
123 }
124 else
125 {
126 va_start(ap, format);
127 vfprintf(stdout, format, ap);
128 va_end(ap);
129 }
130 }
131
132
133 static const char *mus_error_names[MUS_NUM_ERRORS] = {
134 "no error", "no frequency method", "no phase method", "null gen arg to method", "no length method",
135 "no describe method", "no data method", "no scaler method",
136 "memory allocation failed",
137 "can't open file", "no sample input", "no sample output",
138 "no such channel", "no file name provided", "no location method", "no channel method",
139 "no such fft window", "unknown sample type", "header read failed",
140 "unknown header type", "file descriptors not initialized", "not a sound file", "file closed", "write error",
141 "header write failed", "can't open temp file", "interrupted", "bad envelope",
142
143 "audio channels not available", "audio srate not available", "audio sample type not available",
144 "no audio input available", "audio configuration not available",
145 "audio write error", "audio size not available", "audio device not available",
146 "can't close audio", "can't open audio", "audio read error",
147 "can't write audio", "can't read audio", "no audio read permission",
148 "can't close file", "arg out of range",
149
150 "no channels method", "no hop method", "no width method", "no file-name method", "no ramp method", "no run method",
151 "no increment method", "no offset method",
152 "no xcoeff method", "no ycoeff method", "no xcoeffs method", "no ycoeffs method", "no reset", "bad size", "can't convert",
153 "read error",
154 "no feedforward method", "no feedback method", "no interp-type method", "no position method", "no order method", "no copy method",
155 "can't translate"
156 };
157
158
mus_error_type_to_string(int err)159 const char *mus_error_type_to_string(int err)
160 {
161 if ((err >= 0) &&
162 (err < MUS_NUM_ERRORS))
163 return(mus_error_names[err]);
164 return("unknown mus error");
165 }
166
167
default_mus_error(int ignore,char * msg)168 static void default_mus_error(int ignore, char *msg)
169 {
170 /* default error handler simply prints the error message */
171 fprintf(stderr, "%s", msg);
172 }
173
174
local_file_write_date(const char * filename)175 static time_t local_file_write_date(const char *filename)
176 {
177 struct stat statbuf;
178 int err;
179 err = stat(filename, &statbuf);
180 if (err < 0) return((time_t)0);
181 return((time_t)(statbuf.st_mtime));
182 }
183
184
185
186 /* -------- sound file table -------- */
187
188 typedef struct sound_file {
189 char *file_name; /* full path -- everything is keyed to this name */
190 int table_pos, file_name_length, table_index;
191 mus_long_t *aux_comment_start, *aux_comment_end;
192 int *loop_modes, *loop_starts, *loop_ends;
193 int markers, base_detune, base_note;
194 int *marker_ids, *marker_positions;
195 mus_long_t samples, true_file_length;
196 mus_long_t data_location;
197 int srate, chans, original_sound_samp_type, datum_size;
198 mus_header_t header_type;
199 mus_sample_t sample_type;
200 mus_long_t comment_start, comment_end;
201 int type_specifier, bits_per_sample, block_align, fact_samples;
202 time_t write_date;
203 mus_float_t *maxamps;
204 mus_long_t *maxtimes;
205 int maxamps_size; /* we can't depend on sf->chans here because the user could set chans to some bogus value */
206 mus_float_t **saved_data;
207 struct sound_file *next;
208 } sound_file;
209
210 static int *sound_table_sizes = NULL;
211 static sound_file ***sound_tables = NULL;
212 #define NUM_SOUND_TABLES 64
213
214 /* it's not enough to hash on the file name length -- they're nearly all the same length!
215 * I think I'll try taking the last few chars instead (the first 15-20 chars are
216 * also always the same: the tmp directory, eg: /home/bil/zap/tmp/snd_16687_632.snd).
217 */
218
sound_file_hash_index(const char * name,int len)219 static int sound_file_hash_index(const char *name, int len)
220 {
221 unsigned char *s;
222 if (!name) return(0);
223 if (len < 8) return(len);
224 s = (unsigned char *)(name + len - 8);
225 return((int)(s[0] + s[1] + s[2] + s[3]) % (int)NUM_SOUND_TABLES);
226 }
227
228
229 void scan_io_fds_for_saved_data(mus_float_t **data);
230
231 static sound_file *sf_free_list = NULL;
232
free_sound_file(sound_file * sf)233 static void free_sound_file(sound_file *sf)
234 {
235 if (sf)
236 {
237 sound_tables[sf->table_index][sf->table_pos] = NULL;
238 if (sf->aux_comment_start) free(sf->aux_comment_start);
239 if (sf->aux_comment_end) free(sf->aux_comment_end);
240 if (sf->file_name) free(sf->file_name);
241 if (sf->loop_modes) free(sf->loop_modes);
242 if (sf->loop_starts) free(sf->loop_starts);
243 if (sf->loop_ends) free(sf->loop_ends);
244 if (sf->marker_ids) free(sf->marker_ids);
245 if (sf->marker_positions) free(sf->marker_positions);
246 if (sf->maxamps) free(sf->maxamps);
247 if (sf->maxtimes) free(sf->maxtimes);
248 sf->maxamps_size = 0;
249 if (sf->saved_data)
250 {
251 int i;
252 scan_io_fds_for_saved_data(sf->saved_data);
253 for (i = 0; i < sf->chans; i++)
254 if (sf->saved_data[i])
255 free(sf->saved_data[i]);
256 free(sf->saved_data);
257 sf->saved_data = NULL;
258 }
259 /* free(sf); */
260 sf->next = sf_free_list;
261 sf_free_list = sf;
262 }
263 }
264
add_to_sound_table(const char * name)265 static sound_file *add_to_sound_table(const char *name)
266 {
267 int i, len, pos = -1, index, sound_table_size;
268 sound_file **sound_table;
269 sound_file *sf;
270
271 len = strlen(name);
272 index = sound_file_hash_index(name, len);
273
274 sound_table = sound_tables[index];
275 sound_table_size = sound_table_sizes[index];
276
277 for (i = 0; i < sound_table_size; i++)
278 if (!sound_table[i])
279 {
280 pos = i;
281 break;
282 }
283
284 if (pos == -1)
285 {
286 pos = sound_table_size;
287 sound_table_size += 16;
288 if (!sound_table)
289 {
290 sound_table = (sound_file **)calloc(sound_table_size, sizeof(sound_file *));
291 }
292 else
293 {
294 sound_table = (sound_file **)realloc(sound_table, sound_table_size * sizeof(sound_file *));
295 for (i = pos; i < sound_table_size; i++) sound_table[i] = NULL;
296 }
297 sound_tables[index] = sound_table;
298 sound_table_sizes[index] = sound_table_size;
299 }
300
301 if (sf_free_list)
302 {
303 sf = sf_free_list;
304 sf_free_list = sf->next;
305 memset((void *)sf, 0, sizeof(sound_file));
306 }
307 else sf = (sound_file *)calloc(1, sizeof(sound_file));
308 sound_table[pos] = sf;
309 sf->table_pos = pos;
310 sf->table_index = index;
311 sf->file_name = (char *)malloc((len + 1) * sizeof(char));
312 strcpy(sf->file_name, name);
313 sf->file_name[len] = 0;
314 sf->file_name_length = len;
315 sf->saved_data = NULL;
316 return(sf);
317 }
318
319
mus_sound_prune(void)320 int mus_sound_prune(void)
321 {
322 int j, pruned = 0;
323
324 for (j = 0; j < NUM_SOUND_TABLES; j++)
325 {
326 int i, sound_table_size;
327 sound_file **sound_table;
328
329 sound_table = sound_tables[j];
330 sound_table_size = sound_table_sizes[j];
331
332 for (i = 0; i < sound_table_size; i++)
333 if ((sound_table[i]) &&
334 (!(mus_file_probe(sound_table[i]->file_name))))
335 {
336 free_sound_file(sound_table[i]);
337 sound_table[i] = NULL;
338 pruned++;
339 }
340 }
341
342 return(pruned);
343 }
344
345
mus_sound_forget(const char * name)346 int mus_sound_forget(const char *name)
347 {
348 /* apparently here we want to forget either name or the expanded or contracted forms of name -- as many as we find! */
349 int i, len, len2, short_len = 0;
350 bool free_name = false;
351 char *short_name = NULL;
352 sound_file **sound_table;
353 int sound_table_size, index;
354 char c;
355
356 if (!name) return(MUS_ERROR);
357 len = strlen(name);
358 if (len > 6)
359 len2 = len - 6;
360 else len2 = len / 2;
361 c = name[len2];
362
363 if (name[0] == '/')
364 {
365 for (i = 0; i < len; i++)
366 if (name[i] == '/')
367 short_name = (char *)(name + i + 1);
368 }
369 else
370 {
371 short_name = mus_expand_filename(name);
372 free_name = true;
373 }
374 if (short_name)
375 short_len = strlen(short_name);
376
377 index = sound_file_hash_index(name, len);
378 sound_table = sound_tables[index];
379 sound_table_size = sound_table_sizes[index];
380
381 for (i = 0; i < sound_table_size; i++)
382 if ((sound_table[i]) &&
383 (sound_table[i]->file_name_length == len) &&
384 (sound_table[i]->file_name[len2] == c) &&
385 (mus_strcmp(name, sound_table[i]->file_name)))
386 {
387 free_sound_file(sound_table[i]);
388 sound_table[i] = NULL;
389 }
390
391 if (short_name)
392 {
393 if (short_len > 6)
394 len2 = short_len - 6;
395 else len2 = short_len / 2;
396 c = short_name[len2];
397
398 index = sound_file_hash_index(short_name, short_len);
399 sound_table = sound_tables[index];
400 sound_table_size = sound_table_sizes[index];
401
402 for (i = 0; i < sound_table_size; i++)
403 if ((sound_table[i]) &&
404 (sound_table[i]->file_name_length == short_len) &&
405 (sound_table[i]->file_name[len2] == c) &&
406 (mus_strcmp(short_name, sound_table[i]->file_name)))
407 {
408 free_sound_file(sound_table[i]);
409 sound_table[i] = NULL;
410 }
411 }
412
413 if (free_name) free(short_name);
414 return(MUS_NO_ERROR);
415 }
416
417
check_write_date(const char * name,sound_file * sf)418 static sound_file *check_write_date(const char *name, sound_file *sf)
419 {
420 if (sf)
421 {
422 time_t date;
423 date = local_file_write_date(name);
424 if (date == sf->write_date)
425 return(sf);
426
427 if ((sf->header_type == MUS_RAW) && (mus_header_no_header(name)))
428 {
429 int chan;
430 mus_long_t data_size;
431 /* sound has changed since we last read it, but it has no header, so
432 * the only sensible thing to check is the new length (i.e. caller
433 * has set other fields by hand)
434 */
435 sf->write_date = date;
436 chan = mus_file_open_read(name);
437 data_size = lseek(chan, 0L, SEEK_END);
438 sf->true_file_length = data_size;
439 sf->samples = mus_bytes_to_samples(sf->sample_type, data_size);
440 CLOSE(chan, name);
441
442 return(sf);
443 }
444 /* otherwise our data base is out-of-date, so clear it out */
445 free_sound_file(sf);
446 }
447 return(NULL);
448 }
449
450
find_sound_file(const char * name)451 static sound_file *find_sound_file(const char *name)
452 {
453 /* assume name != NULL */
454 int i, len, len2;
455 sound_file **sound_table;
456 int sound_table_size, index;
457 char c;
458
459 len = strlen(name);
460 if (len > 6)
461 len2 = len - 6; /* the names probably all start with '/' and end with ".snd", so try to find a changing character... */
462 else len2 = len / 2;
463 c = name[len2];
464
465 index = sound_file_hash_index(name, len);
466 sound_table = sound_tables[index];
467 sound_table_size = sound_table_sizes[index];
468
469 for (i = 0; i < sound_table_size; i++)
470 {
471 sound_file *sf;
472 sf = sound_table[i];
473 if ((sf) &&
474 (sf->file_name_length == len) &&
475 (c == sf->file_name[len2]) &&
476 (strcmp(name, sf->file_name) == 0))
477 return(check_write_date(name, sf));
478 }
479 return(NULL);
480 }
481
482
display_sound_file_entry(FILE * fp,const char * name,sound_file * sf)483 static void display_sound_file_entry(FILE *fp, const char *name, sound_file *sf)
484 {
485 #define TIME_BUFFER_SIZE 64
486 time_t date;
487 char timestr[TIME_BUFFER_SIZE];
488
489 date = sf->write_date;
490 if (date != 0)
491 strftime(timestr, TIME_BUFFER_SIZE, "%a %d-%b-%Y %H:%M:%S", localtime(&date));
492 else snprintf(timestr, TIME_BUFFER_SIZE, "(date cleared)");
493
494 fprintf(fp, " %s: %s, chans: %d, srate: %d, header: %s, data: %s, samps: %" print_mus_long,
495 name,
496 timestr,
497 sf->chans,
498 sf->srate,
499 mus_header_type_name(sf->header_type),
500 mus_sample_type_name(sf->sample_type),
501 sf->samples);
502
503 if (sf->loop_modes)
504 {
505 if (sf->loop_modes[0] != 0)
506 fprintf(fp, ", loop mode %d: %d to %d", sf->loop_modes[0], sf->loop_starts[0], sf->loop_ends[0]);
507 if (sf->loop_modes[1] != 0)
508 fprintf(fp, ", loop mode %d: %d to %d, ", sf->loop_modes[1], sf->loop_starts[1], sf->loop_ends[1]);
509 fprintf(fp, ", base: %d, detune: %d", sf->base_note, sf->base_detune);
510 }
511
512 if (sf->maxamps)
513 {
514 int lim;
515 lim = sf->maxamps_size;
516 if (lim > 0)
517 {
518 int i;
519 if (lim > 64)
520 lim = 64;
521 fprintf(fp, ", maxamp:");
522 for (i = 0; i < lim; i++)
523 {
524 if (i > 1) fprintf(fp, ", ");
525 fprintf(fp, " %.3f at %.3f ",
526 sf->maxamps[i],
527 (sf->srate > 0) ? ((double)(sf->maxtimes[i]) / (double)(sf->srate)) : (double)(sf->maxtimes[i]));
528 }
529 }
530 }
531
532 if (mus_file_probe(name))
533 {
534 char *comment;
535 comment = mus_sound_comment(name);
536 if (comment)
537 {
538 fprintf(fp, "\n comment: %s", comment);
539 free(comment);
540 }
541 }
542 else fprintf(fp, " [defunct]");
543 fprintf(fp, "\n");
544 }
545
546
mus_sound_report_cache(FILE * fp)547 void mus_sound_report_cache(FILE *fp)
548 {
549 sound_file *sf;
550 int entries = 0;
551 int i, j;
552 sound_file **sound_table;
553
554 fprintf(fp, "sound table:");
555 for (j = 0; j < NUM_SOUND_TABLES; j++)
556 {
557 int sound_table_size;
558 sound_table = sound_tables[j];
559 sound_table_size = sound_table_sizes[j];
560
561 for (i = 0; i < sound_table_size; i++)
562 {
563 sf = sound_table[i];
564 if (sf)
565 {
566 if (entries == 0) fprintf(fp, "\n");
567 display_sound_file_entry(fp, sf->file_name, sf);
568 entries++;
569 }
570 }
571 }
572 if (entries > 0)
573 fprintf(fp, "\nentries: %d\n", entries);
574 else fprintf(fp, " empty");
575 fflush(fp);
576 }
577
578
fill_sf_record(const char * name,sound_file * sf)579 static sound_file *fill_sf_record(const char *name, sound_file *sf)
580 {
581 int i;
582
583 sf->data_location = mus_header_data_location();
584 sf->samples = mus_header_samples();
585 sf->sample_type = mus_header_sample_type();
586 sf->srate = mus_header_srate();
587 /* if (sf->srate < 0) sf->srate = 0; */
588 sf->chans = mus_header_chans();
589 /* if (sf->chans < 0) sf->chans = 0; */
590 sf->datum_size = mus_bytes_per_sample(sf->sample_type);
591 sf->header_type = mus_header_type();
592 sf->original_sound_samp_type = mus_header_original_sample_type();
593 sf->true_file_length = mus_header_true_length();
594
595 sf->comment_start = mus_header_comment_start();
596 sf->comment_end = mus_header_comment_end();
597 if (((sf->header_type == MUS_AIFC) ||
598 (sf->header_type == MUS_AIFF) ||
599 (sf->header_type == MUS_RF64) ||
600 (sf->header_type == MUS_RIFF)) &&
601 (mus_header_aux_comment_start(0) != 0))
602
603 {
604 sf->aux_comment_start = (mus_long_t *)calloc(4, sizeof(mus_long_t));
605 sf->aux_comment_end = (mus_long_t *)calloc(4, sizeof(mus_long_t));
606 for (i = 0; i < 4; i++)
607 {
608 sf->aux_comment_start[i] = mus_header_aux_comment_start(i);
609 sf->aux_comment_end[i] = mus_header_aux_comment_end(i);
610 }
611 }
612
613 sf->type_specifier = mus_header_type_specifier();
614 sf->bits_per_sample = mus_header_bits_per_sample();
615 sf->fact_samples = mus_header_fact_samples();
616 sf->block_align = mus_header_block_align();
617 sf->write_date = local_file_write_date(name);
618
619 if ((sf->header_type == MUS_AIFF) || (sf->header_type == MUS_AIFC))
620 {
621 int *marker_ids, *marker_positions;
622 sf->markers = mus_header_mark_info(&marker_ids, &marker_positions);
623 if (sf->markers > 0)
624 {
625 sf->marker_ids = (int *)malloc(sf->markers * sizeof(int));
626 sf->marker_positions = (int *)malloc(sf->markers * sizeof(int));
627 memcpy((void *)(sf->marker_ids), (void *)marker_ids, sizeof(int) * sf->markers);
628 memcpy((void *)(sf->marker_positions), (void *)marker_positions, sizeof(int) * sf->markers);
629 }
630 }
631
632 if (mus_header_loop_mode(0) > 0)
633 {
634 sf->loop_modes = (int *)calloc(2, sizeof(int));
635 sf->loop_starts = (int *)calloc(2, sizeof(int));
636 sf->loop_ends = (int *)calloc(2, sizeof(int));
637 for (i = 0; i < 2; i++)
638 {
639 sf->loop_modes[i] = mus_header_loop_mode(i);
640 if ((sf->header_type == MUS_AIFF) ||
641 (sf->header_type == MUS_AIFC))
642 {
643 sf->loop_starts[i] = mus_header_mark_position(mus_header_loop_start(i));
644 sf->loop_ends[i] = mus_header_mark_position(mus_header_loop_end(i));
645 }
646 else
647 {
648 sf->loop_starts[i] = mus_header_loop_start(i);
649 sf->loop_ends[i] = mus_header_loop_end(i);
650 }
651 }
652 sf->base_detune = mus_header_base_detune();
653 sf->base_note = mus_header_base_note();
654 }
655
656 return(sf);
657 }
658
659
read_sound_file_header(const char * name)660 static sound_file *read_sound_file_header(const char *name) /* 2 calls on this: mus_sound_open_input and get_sf */
661 {
662 int result;
663 mus_sound_initialize();
664 result = mus_header_read(name);
665 /* this portion won't trigger mus_error */
666 if (result != MUS_ERROR)
667 return(fill_sf_record(name, add_to_sound_table(name))); /* only call on fill_sf_record and add_to_sound_table */
668 return(NULL);
669 }
670
get_sf(const char * arg)671 static sound_file *get_sf(const char *arg)
672 {
673 sound_file *sf = NULL;
674 if (!arg) return(NULL);
675 sf = find_sound_file(arg);
676 return((sf) ? sf : read_sound_file_header(arg));
677 }
678
679
mus_sound_samples(const char * arg)680 mus_long_t mus_sound_samples(const char *arg)
681 {
682 sound_file *sf;
683 sf = get_sf(arg);
684 return((sf) ? sf->samples : (mus_long_t)MUS_ERROR);
685 }
686
687
mus_sound_framples(const char * arg)688 mus_long_t mus_sound_framples(const char *arg)
689 {
690 sound_file *sf;
691 sf = get_sf(arg);
692 return((sf) ? ((sf->chans > 0) ? (sf->samples / sf->chans) : 0) : (mus_long_t)MUS_ERROR);
693 }
694
695
mus_sound_datum_size(const char * arg)696 int mus_sound_datum_size(const char *arg)
697 {
698 sound_file *sf;
699 sf = get_sf(arg);
700 return((sf) ? sf->datum_size : MUS_ERROR);
701 }
702
703
mus_sound_data_location(const char * arg)704 mus_long_t mus_sound_data_location(const char *arg)
705 {
706 sound_file *sf;
707 sf = get_sf(arg);
708 return((sf) ? sf->data_location : MUS_ERROR);
709 }
710
711
mus_sound_chans(const char * arg)712 int mus_sound_chans(const char *arg)
713 {
714 sound_file *sf;
715 sf = get_sf(arg);
716 return((sf) ? sf->chans : MUS_ERROR);
717 }
718
719
mus_sound_srate(const char * arg)720 int mus_sound_srate(const char *arg)
721 {
722 sound_file *sf;
723 sf = get_sf(arg);
724 return((sf) ? sf->srate : MUS_ERROR);
725 }
726
727
mus_sound_header_type(const char * arg)728 mus_header_t mus_sound_header_type(const char *arg)
729 {
730 sound_file *sf;
731 sf = get_sf(arg);
732 return((sf) ? sf->header_type : MUS_UNKNOWN_HEADER);
733 }
734
735
mus_sound_sample_type(const char * arg)736 mus_sample_t mus_sound_sample_type(const char *arg)
737 {
738 sound_file *sf;
739 sf = get_sf(arg);
740 return((sf) ? sf->sample_type : MUS_UNKNOWN_SAMPLE);
741 }
742
743
mus_sound_original_sample_type(const char * arg)744 int mus_sound_original_sample_type(const char *arg)
745 {
746 sound_file *sf;
747 sf = get_sf(arg);
748 return((sf) ? sf->original_sound_samp_type : MUS_ERROR);
749 }
750
751
mus_sound_comment_start(const char * arg)752 mus_long_t mus_sound_comment_start(const char *arg)
753 {
754 sound_file *sf;
755 sf = get_sf(arg);
756 return((sf) ? sf->comment_start : (mus_long_t)MUS_ERROR);
757 }
758
759
mus_sound_comment_end(const char * arg)760 mus_long_t mus_sound_comment_end(const char *arg)
761 {
762 sound_file *sf;
763 sf = get_sf(arg);
764 return((sf) ? sf->comment_end : (mus_long_t)MUS_ERROR);
765 }
766
767
mus_sound_length(const char * arg)768 mus_long_t mus_sound_length(const char *arg)
769 {
770 sound_file *sf;
771 sf = get_sf(arg);
772 return((sf) ? sf->true_file_length : (mus_long_t)MUS_ERROR);
773 }
774
775
mus_sound_fact_samples(const char * arg)776 int mus_sound_fact_samples(const char *arg)
777 {
778 sound_file *sf;
779 sf = get_sf(arg);
780 return((sf) ? sf->fact_samples : MUS_ERROR);
781 }
782
783
mus_sound_write_date(const char * arg)784 time_t mus_sound_write_date(const char *arg)
785 {
786 sound_file *sf;
787 sf = get_sf(arg);
788 return((sf) ? sf->write_date : (time_t)MUS_ERROR);
789 }
790
791
mus_sound_type_specifier(const char * arg)792 int mus_sound_type_specifier(const char *arg)
793 {
794 sound_file *sf;
795 sf = get_sf(arg);
796 return((sf) ? sf->type_specifier : MUS_ERROR);
797 }
798
799
mus_sound_block_align(const char * arg)800 int mus_sound_block_align(const char *arg)
801 {
802 sound_file *sf;
803 sf = get_sf(arg);
804 return((sf) ? sf->block_align : MUS_ERROR);
805 }
806
807
mus_sound_bits_per_sample(const char * arg)808 int mus_sound_bits_per_sample(const char *arg)
809 {
810 sound_file *sf;
811 sf = get_sf(arg);
812 return((sf) ? sf->bits_per_sample : MUS_ERROR);
813 }
814
815
mus_sound_duration(const char * arg)816 float mus_sound_duration(const char *arg)
817 {
818 float val = -1.0;
819 sound_file *sf;
820 sf = get_sf(arg);
821 if (sf)
822 {
823 if ((sf->chans > 0) && (sf->srate > 0))
824 val = ((double)(sf->samples) / ((double)(sf->chans) * (double)(sf->srate)));
825 else val = 0.0;
826 }
827 return(val);
828 }
829
830
mus_sound_saved_data(const char * arg)831 mus_float_t **mus_sound_saved_data(const char *arg)
832 {
833 /* slightly tricky -- we don't want to trigger a sound_file table entry here!
834 */
835 sound_file *sf;
836 if (!arg) return(NULL);
837 sf = find_sound_file(arg); /* not get_sf which will make an entry in the table */
838 return((sf) ? sf->saved_data : NULL);
839 }
840
841
mus_sound_set_saved_data(const char * arg,mus_float_t ** data)842 void mus_sound_set_saved_data(const char *arg, mus_float_t **data)
843 {
844 sound_file *sf;
845 sf = get_sf(arg);
846 if (sf)
847 sf->saved_data = data;
848 }
849
850
mus_sound_loop_info(const char * arg)851 int *mus_sound_loop_info(const char *arg)
852 {
853 sound_file *sf;
854 sf = get_sf(arg);
855 if ((sf) && (sf->loop_modes))
856 {
857 int *info;
858 info = (int *)calloc(MUS_LOOP_INFO_SIZE, sizeof(int));
859 if (sf->loop_modes[0] != 0)
860 {
861 info[0] = sf->loop_starts[0];
862 info[1] = sf->loop_ends[0];
863 info[6] = sf->loop_modes[0];
864 }
865 if (sf->loop_modes[1] != 0)
866 {
867 info[2] = sf->loop_starts[1];
868 info[3] = sf->loop_ends[1];
869 info[7] = sf->loop_modes[1];
870 }
871 info[4] = sf->base_note;
872 info[5] = sf->base_detune;
873 return(info);
874 }
875 return(NULL);
876 }
877
878
mus_sound_set_loop_info(const char * arg,int * loop)879 void mus_sound_set_loop_info(const char *arg, int *loop)
880 {
881 sound_file *sf;
882 sf = get_sf(arg);
883 if (sf)
884 {
885 if (!sf->loop_modes)
886 {
887 sf->loop_modes = (int *)calloc(2, sizeof(int));
888 sf->loop_starts = (int *)calloc(2, sizeof(int));
889 sf->loop_ends = (int *)calloc(2, sizeof(int));
890 }
891 sf->loop_modes[0] = loop[6];
892 if (loop[6] != 0)
893 {
894 sf->loop_starts[0] = loop[0];
895 sf->loop_ends[0] = loop[1];
896 }
897 else
898 {
899 sf->loop_starts[0] = 0;
900 sf->loop_ends[0] = 0;
901 }
902 sf->loop_modes[1] = loop[7];
903 if (loop[7] != 0)
904 {
905 sf->loop_starts[1] = loop[2];
906 sf->loop_ends[1] = loop[3];
907 }
908 else
909 {
910 sf->loop_starts[1] = 0;
911 sf->loop_ends[1] = 0;
912 }
913 sf->base_note = loop[4];
914 sf->base_detune = loop[5];
915 }
916 }
917
918
mus_sound_mark_info(const char * arg,int ** mark_ids,int ** mark_positions)919 int mus_sound_mark_info(const char *arg, int **mark_ids, int **mark_positions)
920 {
921 sound_file *sf;
922 int result = 0;
923 sf = get_sf(arg);
924 if (sf)
925 {
926 (*mark_ids) = sf->marker_ids;
927 (*mark_positions) = sf->marker_positions;
928 result = sf->markers;
929 }
930 return(result);
931 }
932
933
mus_sound_comment(const char * name)934 char *mus_sound_comment(const char *name)
935 {
936 char *sc = NULL;
937 sound_file *sf;
938 sf = get_sf(name);
939 if (sf)
940 {
941 mus_long_t start, end;
942 start = sf->comment_start;
943 end = sf->comment_end;
944 if (end == 0)
945 {
946 if (sf->aux_comment_start)
947 {
948 if ((sf->header_type == MUS_RIFF) ||
949 (sf->header_type == MUS_RF64))
950 sc = mus_header_riff_aux_comment(name,
951 sf->aux_comment_start,
952 sf->aux_comment_end);
953 if ((sf->header_type == MUS_AIFF) ||
954 (sf->header_type == MUS_AIFC))
955 sc = mus_header_aiff_aux_comment(name,
956 sf->aux_comment_start,
957 sf->aux_comment_end);
958 }
959 }
960 else
961 {
962 if (end <= sf->true_file_length)
963 {
964 int len;
965 len = end - start + 1;
966 if (len > 0)
967 {
968 /* open and get the comment */
969 ssize_t bytes;
970 int fd;
971 fd = mus_file_open_read(name);
972 if (fd == -1) return(NULL);
973 lseek(fd, start, SEEK_SET);
974 sc = (char *)calloc(len + 1, sizeof(char));
975 bytes = read(fd, sc, len);
976 CLOSE(fd, name);
977 if (((sf->header_type == MUS_AIFF) ||
978 (sf->header_type == MUS_AIFC)) &&
979 (sf->aux_comment_start) &&
980 (bytes != 0))
981 {
982 char *auxcom;
983 auxcom = mus_header_aiff_aux_comment(name,
984 sf->aux_comment_start,
985 sf->aux_comment_end);
986 if (auxcom)
987 {
988 size_t full_len;
989 full_len = strlen(auxcom) + strlen(sc) + 2;
990 sc = (char *)realloc(sc, full_len * sizeof(char));
991 strcat(sc, "\n");
992 strcat(sc, auxcom);
993 }
994 }
995 }
996 }
997 }
998 }
999 return(sc);
1000 }
1001
1002
mus_sound_open_input(const char * arg)1003 int mus_sound_open_input(const char *arg)
1004 {
1005 int fd = -1;
1006 if (!(mus_file_probe(arg)))
1007 mus_error(MUS_CANT_OPEN_FILE, "mus_sound_open_input: can't open %s: %s", arg, STRERROR(errno));
1008 else
1009 {
1010 sound_file *sf;
1011 mus_sound_initialize();
1012 sf = get_sf(arg);
1013 if (sf)
1014 {
1015 fd = mus_file_open_read(arg);
1016 if (fd == -1)
1017 mus_error(MUS_CANT_OPEN_FILE, "mus_sound_open_input: can't open %s: %s", arg, STRERROR(errno));
1018 else
1019 {
1020 mus_file_open_descriptors(fd, arg, sf->sample_type, sf->datum_size, sf->data_location, sf->chans, sf->header_type);
1021 lseek(fd, sf->data_location, SEEK_SET);
1022 if (sf->saved_data)
1023 mus_file_save_data(fd, sf->samples / sf->chans, sf->saved_data);
1024 }
1025 }
1026 }
1027 return(fd);
1028 }
1029
1030
mus_sound_open_output(const char * arg,int srate,int chans,mus_sample_t sample_type,mus_header_t header_type,const char * comment)1031 int mus_sound_open_output(const char *arg, int srate, int chans, mus_sample_t sample_type, mus_header_t header_type, const char *comment)
1032 {
1033 int fd = MUS_ERROR, err;
1034 mus_sound_initialize();
1035 mus_sound_forget(arg);
1036 err = mus_write_header(arg, header_type, srate, chans, 0, sample_type, comment);
1037 if (err != MUS_ERROR)
1038 {
1039 fd = mus_file_open_write(arg);
1040 if (fd != -1)
1041 mus_file_open_descriptors(fd,
1042 arg,
1043 sample_type,
1044 mus_bytes_per_sample(sample_type),
1045 mus_header_data_location(),
1046 chans,
1047 header_type);
1048 }
1049 return(fd);
1050 }
1051
1052
mus_sound_reopen_output(const char * arg,int chans,mus_sample_t samp_type,mus_header_t type,mus_long_t data_loc)1053 int mus_sound_reopen_output(const char *arg, int chans, mus_sample_t samp_type, mus_header_t type, mus_long_t data_loc)
1054 {
1055 int fd;
1056 mus_sound_initialize();
1057 fd = mus_file_reopen_write(arg);
1058 if (fd != -1)
1059 mus_file_open_descriptors(fd, arg, samp_type, mus_bytes_per_sample(samp_type), data_loc, chans, type);
1060 return(fd);
1061 }
1062
1063
mus_sound_close_input(int fd)1064 int mus_sound_close_input(int fd)
1065 {
1066 return(mus_file_close(fd)); /* this closes the clm file descriptors */
1067 }
1068
1069
mus_sound_close_output(int fd,mus_long_t bytes_of_data)1070 int mus_sound_close_output(int fd, mus_long_t bytes_of_data)
1071 {
1072 char *name;
1073 name = mus_file_fd_name(fd);
1074 if (name)
1075 {
1076 int err;
1077 mus_header_t old_type;
1078 char *fname;
1079 fname = mus_strdup(name);
1080 old_type = mus_file_header_type(fd);
1081 err = mus_file_close(fd); /* this frees the original fd->name, so we copied above */
1082 /* fd is NULL now */
1083 mus_sound_forget(fname);
1084 mus_header_change_data_size(fname, old_type, bytes_of_data);
1085 free(fname);
1086 return(err);
1087 }
1088 return(MUS_ERROR);
1089 }
1090
1091
1092 typedef enum {SF_CHANS, SF_SRATE, SF_TYPE, SF_SAMP_TYPE, SF_LOCATION, SF_SIZE} sf_field_t;
1093
mus_sound_set_field(const char * arg,sf_field_t field,int val)1094 static int mus_sound_set_field(const char *arg, sf_field_t field, int val)
1095 {
1096 sound_file *sf;
1097 int result = MUS_NO_ERROR;
1098
1099 sf = get_sf(arg);
1100 if (sf)
1101 {
1102 switch (field)
1103 {
1104 case SF_CHANS:
1105 sf->chans = val;
1106 break;
1107
1108 case SF_SRATE:
1109 sf->srate = val;
1110 break;
1111
1112 case SF_TYPE:
1113 sf->header_type = (mus_header_t)val;
1114 break;
1115
1116 case SF_SAMP_TYPE:
1117 sf->sample_type = (mus_sample_t)val;
1118 sf->datum_size = mus_bytes_per_sample(sf->sample_type);
1119 break;
1120
1121 default:
1122 result = MUS_ERROR;
1123 break;
1124 }
1125 }
1126 else result = MUS_ERROR;
1127 return(result);
1128 }
1129
1130
mus_sound_set_mus_long_t_field(const char * arg,sf_field_t field,mus_long_t val)1131 static int mus_sound_set_mus_long_t_field(const char *arg, sf_field_t field, mus_long_t val)
1132 {
1133 sound_file *sf;
1134 int result = MUS_NO_ERROR;
1135
1136 sf = get_sf(arg);
1137 if (sf)
1138 {
1139 switch (field)
1140 {
1141 case SF_SIZE:
1142 sf->samples = val;
1143 break;
1144
1145 case SF_LOCATION:
1146 sf->data_location = val;
1147 break;
1148
1149 default:
1150 result = MUS_ERROR;
1151 break;
1152 }
1153 }
1154 else result = MUS_ERROR;
1155
1156 return(result);
1157 }
1158
1159
mus_sound_set_chans(const char * arg,int val)1160 int mus_sound_set_chans(const char *arg, int val) {return(mus_sound_set_field(arg, SF_CHANS, val));}
mus_sound_set_srate(const char * arg,int val)1161 int mus_sound_set_srate(const char *arg, int val) {return(mus_sound_set_field(arg, SF_SRATE, val));}
mus_sound_set_header_type(const char * arg,mus_header_t val)1162 mus_header_t mus_sound_set_header_type(const char *arg, mus_header_t val) {return((mus_header_t)mus_sound_set_field(arg, SF_TYPE, val));}
mus_sound_set_sample_type(const char * arg,mus_sample_t val)1163 mus_sample_t mus_sound_set_sample_type(const char *arg, mus_sample_t val) {return((mus_sample_t)mus_sound_set_field(arg, SF_SAMP_TYPE, val));}
mus_sound_set_data_location(const char * arg,mus_long_t val)1164 int mus_sound_set_data_location(const char *arg, mus_long_t val) {return(mus_sound_set_mus_long_t_field(arg, SF_LOCATION, val));}
mus_sound_set_samples(const char * arg,mus_long_t val)1165 int mus_sound_set_samples(const char *arg, mus_long_t val) {return(mus_sound_set_mus_long_t_field(arg, SF_SIZE, val));}
1166
1167
mus_sound_override_header(const char * arg,int srate,int chans,mus_sample_t samp_type,mus_header_t type,mus_long_t location,mus_long_t size)1168 int mus_sound_override_header(const char *arg, int srate, int chans, mus_sample_t samp_type, mus_header_t type, mus_long_t location, mus_long_t size)
1169 {
1170 sound_file *sf;
1171 int result = MUS_NO_ERROR;
1172 /* perhaps once a header has been over-ridden, we should not reset the relevant fields upon re-read? */
1173
1174 sf = get_sf(arg);
1175 if (sf)
1176 {
1177 if (location != -1) sf->data_location = location;
1178 if (size != -1) sf->samples = size;
1179 if (samp_type != MUS_UNKNOWN_SAMPLE)
1180 {
1181 sf->sample_type = samp_type;
1182 sf->datum_size = mus_bytes_per_sample(samp_type);
1183 }
1184 if (srate != -1) sf->srate = srate;
1185 if (chans != -1) sf->chans = chans;
1186 if (type != MUS_UNKNOWN_HEADER) sf->header_type = (mus_header_t)type;
1187 }
1188 else result = MUS_ERROR;
1189
1190 return(result);
1191 }
1192
1193
mus_sound_maxamp_exists(const char * ifile)1194 bool mus_sound_maxamp_exists(const char *ifile)
1195 {
1196 sound_file *sf;
1197 sf = get_sf(ifile);
1198 if ((sf) && (sf->maxtimes))
1199 {
1200 int i;
1201 for (i = 0; i < sf->maxamps_size; i++)
1202 if (sf->maxtimes[i] == -1)
1203 return(false);
1204 return(true);
1205 }
1206 return(false);
1207 }
1208
1209
mus_sound_maxamps(const char * ifile,int chans,mus_float_t * vals,mus_long_t * times)1210 mus_long_t mus_sound_maxamps(const char *ifile, int chans, mus_float_t *vals, mus_long_t *times)
1211 {
1212 mus_long_t framples;
1213 uint32_t ichans, chn;
1214 sound_file *sf;
1215
1216 sf = get_sf(ifile);
1217 if (sf->chans <= 0)
1218 return(MUS_ERROR);
1219
1220 if ((sf) && (sf->maxamps))
1221 {
1222 if (chans > sf->maxamps_size)
1223 ichans = sf->maxamps_size;
1224 else ichans = (uint32_t)chans;
1225 for (chn = 0; chn < ichans; chn++)
1226 {
1227 times[chn] = sf->maxtimes[chn];
1228 vals[chn] = sf->maxamps[chn];
1229 }
1230 framples = sf->samples / sf->chans;
1231 return(framples);
1232 }
1233
1234 {
1235 int j, bufnum, ifd;
1236 mus_long_t n, curframples;
1237 mus_float_t *buffer, *samp;
1238 mus_long_t *time;
1239 mus_float_t **ibufs;
1240
1241 ifd = mus_sound_open_input(ifile);
1242 if (ifd == MUS_ERROR) return(MUS_ERROR);
1243 ichans = (uint32_t)mus_sound_chans(ifile);
1244 framples = mus_sound_framples(ifile);
1245 if ((framples == 0) || (ichans > MUS_MAX_CHANS))
1246 {
1247 mus_sound_close_input(ifd);
1248 return(0);
1249 }
1250
1251 mus_file_seek_frample(ifd, 0);
1252
1253 ibufs = (mus_float_t **)calloc(ichans, sizeof(mus_float_t *));
1254 bufnum = 8192;
1255 for (chn = 0; chn < ichans; chn++)
1256 ibufs[chn] = (mus_float_t *)calloc(bufnum, sizeof(mus_float_t));
1257
1258 time = (mus_long_t *)calloc(ichans, sizeof(mus_long_t));
1259 samp = (mus_float_t *)calloc(ichans, sizeof(mus_float_t));
1260
1261 for (n = 0; n < framples; n += bufnum)
1262 {
1263 if ((n + bufnum) < framples)
1264 curframples = bufnum;
1265 else curframples = (framples - n);
1266 mus_file_read(ifd, n, curframples, ichans, ibufs);
1267 for (chn = 0; chn < ichans; chn++)
1268 {
1269 int i;
1270 buffer = (mus_float_t *)(ibufs[chn]);
1271 for (i = 0; i < curframples; i++)
1272 {
1273 mus_float_t abs_samp;
1274 abs_samp = fabs(buffer[i]);
1275 if (abs_samp > samp[chn])
1276 {
1277 time[chn] = i + n;
1278 samp[chn] = abs_samp;
1279 }
1280 }
1281 }
1282 }
1283
1284 mus_sound_close_input(ifd);
1285 /* fprintf(stderr, "set in mus_sound_maxamps\n"); */
1286 mus_sound_set_maxamps(ifile, ichans, samp, time); /* save the complete set */
1287
1288 if ((int)ichans > chans) ichans = chans;
1289 for (chn = 0; chn < ichans; chn++)
1290 {
1291 times[chn] = time[chn];
1292 vals[chn] = samp[chn];
1293 }
1294 free(time);
1295 free(samp);
1296 for (j = 0; j < (int)ichans; j++) free(ibufs[j]);
1297 free(ibufs);
1298 return(framples);
1299 }
1300 }
1301
1302
mus_sound_set_maxamps(const char * ifile,int chans,mus_float_t * vals,mus_long_t * times)1303 int mus_sound_set_maxamps(const char *ifile, int chans, mus_float_t *vals, mus_long_t *times)
1304 {
1305 sound_file *sf;
1306 int result = MUS_NO_ERROR;
1307
1308 /* fprintf(stderr, "set %s maxamps: %d %.3f %" print_mus_long "\n", ifile, chans, vals[0], times[0]); */
1309 sf = get_sf(ifile);
1310 if (sf)
1311 {
1312 int i, ichans = 0;
1313
1314 if (sf->maxamps)
1315 {
1316 if (chans > sf->maxamps_size)
1317 ichans = sf->maxamps_size;
1318 else ichans = chans;
1319 for (i = 0; i < ichans; i++)
1320 {
1321 sf->maxtimes[i] = times[i];
1322 sf->maxamps[i] = vals[i];
1323 }
1324 }
1325 else
1326 {
1327 ichans = sf->chans;
1328 if (!sf->maxamps)
1329 {
1330 /* here we need to use the max, since the caller may be confused */
1331 int max_chans;
1332 max_chans = ichans;
1333 if (max_chans < chans)
1334 max_chans = chans;
1335
1336 sf->maxamps = (mus_float_t *)calloc(max_chans, sizeof(mus_float_t));
1337 sf->maxtimes = (mus_long_t *)calloc(max_chans, sizeof(mus_long_t));
1338 sf->maxamps_size = max_chans;
1339 }
1340 if (ichans > sf->maxamps_size)
1341 ichans = sf->maxamps_size;
1342
1343 if (ichans > chans)
1344 ichans = chans;
1345 for (i = 0; i < ichans; i++)
1346 {
1347 sf->maxtimes[i] = times[i];
1348 sf->maxamps[i] = vals[i];
1349 }
1350 }
1351 }
1352 else result = MUS_ERROR;
1353 return(result);
1354 }
1355
1356
mus_sound_channel_maxamp_exists(const char * file,int chan)1357 bool mus_sound_channel_maxamp_exists(const char *file, int chan)
1358 {
1359 sound_file *sf;
1360 sf = get_sf(file);
1361 return((sf) &&
1362 (sf->maxtimes) &&
1363 (sf->maxamps_size > chan) &&
1364 (sf->maxtimes[chan] != -1));
1365 }
1366
1367
mus_sound_channel_maxamp(const char * file,int chan,mus_long_t * pos)1368 mus_float_t mus_sound_channel_maxamp(const char *file, int chan, mus_long_t *pos)
1369 {
1370 sound_file *sf;
1371 sf = get_sf(file);
1372 if ((chan < sf->maxamps_size) &&
1373 (sf->maxtimes))
1374 {
1375 (*pos) = sf->maxtimes[chan];
1376 return(sf->maxamps[chan]);
1377 }
1378 return(-1.0);
1379 }
1380
1381
mus_sound_channel_set_maxamp(const char * file,int chan,mus_float_t mx,mus_long_t pos)1382 void mus_sound_channel_set_maxamp(const char *file, int chan, mus_float_t mx, mus_long_t pos)
1383 {
1384 sound_file *sf;
1385 /* fprintf(stderr, "set %s maxamp: %.3f %" print_mus_long "\n", file, mx, pos); */
1386 sf = get_sf(file);
1387 if ((sf) &&
1388 (sf->chans > chan))
1389 {
1390 if (!(sf->maxamps))
1391 {
1392 int i;
1393 sf->maxamps = (mus_float_t *)malloc(sf->chans * sizeof(mus_float_t));
1394 sf->maxtimes = (mus_long_t *)malloc(sf->chans * sizeof(mus_long_t));
1395 sf->maxamps_size = sf->chans;
1396 for (i = 0; i < sf->chans; i++)
1397 {
1398 sf->maxamps[i] = -1.0;
1399 sf->maxtimes[i] = -1;
1400 }
1401 }
1402 sf->maxamps[chan] = mx;
1403 sf->maxtimes[chan] = pos;
1404 }
1405 }
1406
1407
mus_file_to_array(const char * filename,int chan,mus_long_t start,mus_long_t samples,mus_float_t * array)1408 mus_long_t mus_file_to_array(const char *filename, int chan, mus_long_t start, mus_long_t samples, mus_float_t *array)
1409 {
1410 int ifd, chans;
1411 mus_long_t total_read;
1412 mus_float_t **bufs;
1413
1414 ifd = mus_sound_open_input(filename);
1415 if (ifd == MUS_ERROR) return(MUS_ERROR);
1416
1417 chans = mus_sound_chans(filename);
1418 if ((chan >= chans) ||
1419 (chan < 0))
1420 {
1421 mus_sound_close_input(ifd);
1422 return(mus_error(MUS_NO_SUCH_CHANNEL, "mus_file_to_array can't read %s channel %d (file has %d chans)", filename, chan, chans));
1423 }
1424
1425 bufs = (mus_float_t **)calloc(chans, sizeof(mus_float_t *));
1426 bufs[chan] = array;
1427
1428 mus_file_seek_frample(ifd, start);
1429 total_read = mus_file_read_any(ifd, start, chans, samples, bufs, bufs);
1430
1431 mus_sound_close_input(ifd);
1432 free(bufs);
1433
1434 return(total_read);
1435 }
1436
1437
mus_array_to_file_with_error(const char * filename,mus_float_t * ddata,mus_long_t len,int srate,int channels)1438 const char *mus_array_to_file_with_error(const char *filename, mus_float_t *ddata, mus_long_t len, int srate, int channels)
1439 {
1440 /* put ddata into a sound file, taking byte order into account */
1441 /* assume ddata is interleaved already if more than one channel */
1442 int fd, err;
1443 mus_long_t oloc;
1444 mus_sound_forget(filename);
1445
1446 err = mus_write_header(filename, MUS_NEXT, srate, channels, len * channels, MUS_OUT_SAMPLE_TYPE, "array->file");
1447 if (err != MUS_NO_ERROR)
1448 return("mus_array_to_file can't create output file");
1449 oloc = mus_header_data_location();
1450 fd = mus_file_reopen_write(filename);
1451 lseek(fd, oloc, SEEK_SET);
1452 err = mus_file_open_descriptors(fd, filename,
1453 MUS_OUT_SAMPLE_TYPE,
1454 mus_bytes_per_sample(MUS_OUT_SAMPLE_TYPE),
1455 oloc, channels, MUS_NEXT);
1456 if (err != MUS_ERROR)
1457 {
1458 mus_float_t *bufs[1];
1459 bufs[0] = ddata;
1460 err = mus_file_write(fd, 0, len - 1, 1, bufs); /* 1 = chans?? */
1461 }
1462 mus_file_close(fd);
1463 if (err == MUS_ERROR)
1464 return("mus_array_to_file write error");
1465 return(NULL);
1466 }
1467
mus_array_to_file(const char * filename,mus_float_t * ddata,mus_long_t len,int srate,int channels)1468 int mus_array_to_file(const char *filename, mus_float_t *ddata, mus_long_t len, int srate, int channels)
1469 {
1470 const char *errmsg;
1471 errmsg = mus_array_to_file_with_error(filename, ddata, len, srate, channels);
1472 if (errmsg)
1473 return(mus_error(MUS_CANT_OPEN_FILE, "%s", errmsg));
1474 return(MUS_NO_ERROR);
1475 }
1476
1477
mus_file_to_float_array(const char * filename,int chan,mus_long_t start,mus_long_t samples,mus_float_t * array)1478 mus_long_t mus_file_to_float_array(const char *filename, int chan, mus_long_t start, mus_long_t samples, mus_float_t *array)
1479 {
1480 return(mus_file_to_array(filename, chan, start, samples, array));
1481 }
1482
1483
mus_float_array_to_file(const char * filename,mus_float_t * ddata,mus_long_t len,int srate,int channels)1484 int mus_float_array_to_file(const char *filename, mus_float_t *ddata, mus_long_t len, int srate, int channels)
1485 {
1486 const char *errmsg;
1487 errmsg = mus_array_to_file_with_error(filename, ddata, len, srate, channels);
1488 if (errmsg)
1489 return(mus_error(MUS_CANT_OPEN_FILE, "%s", errmsg));
1490
1491 return(MUS_NO_ERROR);
1492 }
1493
1494
mus_sound_initialize(void)1495 int mus_sound_initialize(void)
1496 {
1497 static bool sndlib_initialized = false;
1498 if (!sndlib_initialized)
1499 {
1500 int err;
1501 sndlib_initialized = true;
1502 mus_error_handler = default_mus_error;
1503 err = mus_header_initialize();
1504 if (err == MUS_NO_ERROR)
1505 err = mus_audio_initialize();
1506 sound_tables = (sound_file ***)calloc(NUM_SOUND_TABLES, sizeof(sound_file **));
1507 sound_table_sizes = (int *)calloc(NUM_SOUND_TABLES, sizeof(int));
1508 return(err);
1509 }
1510 return(MUS_NO_ERROR);
1511 }
1512
1513
1514