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