1 #if (defined(__GNUC__)) && (!(defined(__cplusplus)))
2   #define _GNU_SOURCE
3   /* this is needed to get the vasprintf declaration */
4 #endif
5 
6 #include "snd.h"
7 
8 
snd_round(double x)9 int snd_round(double x) /* needs to be double here (not mus_float_t) for x axis calcs */
10 {
11   int i;
12   i = (int)x;
13   if ((x - i) > 0.5) return(i + 1);
14   return(i);
15 }
16 
17 
snd_round_mus_long_t(double x)18 mus_long_t snd_round_mus_long_t(double x)
19 {
20   mus_long_t i;
21   i = (mus_long_t)x;
22   if ((x - i) > 0.5) return(i + 1);
23   return(i);
24 }
25 
26 
snd_abs_mus_long_t(mus_long_t val)27 mus_long_t snd_abs_mus_long_t(mus_long_t val)
28 {
29   /* div is also limited to int */
30   return((val < 0) ? -val : val);
31 }
32 
33 
34 #define POW2_SIZE 31
35 static int ipow2s[POW2_SIZE] = {1, 2, 4, 8, 16, 32, 64, 128, 256,
36 				512, 1024, 2048, 4096, 8192, 16384, 32768, 65536,
37 				131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216,
38 				33554432, 67108864, 134217728, 268435456, 536870912, 1073741824};
snd_int_pow2(int n)39 int snd_int_pow2(int n)
40 {
41   return(ipow2s[n]);
42 }
43 
44 
snd_mus_long_t_pow2(int n)45 mus_long_t snd_mus_long_t_pow2(int n)
46 {
47   if ((n < 0) || (n > 46)) return(0);
48   if (n < POW2_SIZE)
49     return((mus_long_t)ipow2s[n]);
50   return((mus_long_t)ipow2s[16] * (mus_long_t)ipow2s[n - 16]);  /* can't store an array as above -- compiler complaints */
51 }
52 
53 
snd_to_int_pow2(int n)54 int snd_to_int_pow2(int n)
55 {
56   /* round up to next power of 2 */
57   int i;
58   for (i = 0; i < POW2_SIZE; i++)
59     if (ipow2s[i] >= n)
60       return(ipow2s[i]);
61   return(0);
62 }
63 
64 
snd_int_log2(int n)65 int snd_int_log2(int n)
66 {
67   /* round down */
68   int i;
69   for (i = 1; i < POW2_SIZE; i++)
70     if (ipow2s[i] > n)
71       return(i - 1);
72   return(0);
73 }
74 
75 
76 #define MAX_FLOAT_DIFF_FOR_EQUAL 0.0000001
77 
snd_feq(mus_float_t val1,mus_float_t val2)78 bool snd_feq(mus_float_t val1, mus_float_t val2)
79 {
80   /* if some float can be affected by a widget, we can easily get float inaccuracies that confuse "==" */
81   if (val1 == val2) return(true);
82   if (fabs(val1 - val2) < MAX_FLOAT_DIFF_FOR_EQUAL) return(true);
83   return(false);
84 }
85 
86 
87 #if !(defined(__GNUC__) && (!(defined(__cplusplus))))
in_dB(mus_float_t min_dB,mus_float_t lin_dB,mus_float_t val)88 mus_float_t in_dB(mus_float_t min_dB, mus_float_t lin_dB, mus_float_t val)
89 {
90   return((val <= lin_dB) ? min_dB : (20.0 * log10(val)));
91 }
92 #endif
93 
94 
95 #define TIME_STR_SIZE 64
96 static char time_buf[TIME_STR_SIZE];
97 
snd_local_time(void)98 char *snd_local_time(void)
99 {
100   time_t ts;
101   time(&ts);
102   strftime(time_buf, TIME_STR_SIZE, STRFTIME_FORMAT, localtime(&ts));
103   return(time_buf);
104 }
105 
106 
snd_strftime(const char * format,time_t date)107 char *snd_strftime(const char *format, time_t date)
108 {
109   strftime(time_buf, TIME_STR_SIZE, format, localtime(&date));
110   return(time_buf);
111 }
112 
113 
snd_io_strerror(void)114 char *snd_io_strerror(void) /* "snd_strerror" is exported by ALSA! */
115 {
116   if (ss->local_errno != 0)
117     return(strerror(ss->local_errno));
118   if (errno != 0)
119     return(strerror(errno));
120   return(NULL);
121 }
122 
123 
snd_open_strerror(void)124 char *snd_open_strerror(void)
125 {
126   if (ss->local_open_errno != 0)
127     return(strerror(ss->local_open_errno));
128   return(snd_io_strerror());
129 }
130 
131 
string_to_colon(char * val)132 char *string_to_colon(char *val)
133 {
134   char *up_to_colon;
135   int i, len;
136   up_to_colon = (char *)calloc(strlen(val) + 1, sizeof(char));
137   len = strlen(val);
138   for (i = 0; i < len; i++)
139     {
140       if ((val[i] == ':') || (val[i] == ' '))
141 	{
142 	  up_to_colon[i] = 0;
143 	  return(up_to_colon);
144 	}
145       up_to_colon[i] = val[i];
146     }
147   return(up_to_colon);
148 }
149 
150 
filename_without_directory(const char * name)151 char *filename_without_directory(const char *name)
152 {
153   /* since I don't want to mess with freeing these guys, I'll just return a pointer into the name */
154   int i, len, last_slash;
155   last_slash = 0;
156   len = strlen(name);
157   for (i = 0; i < len - 1; i++)
158     if (name[i] == '/')
159       last_slash = i + 1;
160   return((char *)(name + last_slash));
161 }
162 
163 
just_filename(char * name)164 char *just_filename(char *name)
165 {
166   char *nodir;
167   int i, len;
168   nodir = mus_strdup(filename_without_directory(name));
169   len = strlen(nodir);
170   for (i = 0; i < len; i++)
171     if (nodir[i] == '.')
172       {
173 	nodir[i] = '\0';
174 	break;
175       }
176   return(nodir);
177 }
178 
179 
just_directory(const char * name)180 char *just_directory(const char *name)
181 {
182   int i, len, last_slash = 0;
183   char *dirname;
184   len = strlen(name);
185   dirname = (char *)calloc(len + 1, sizeof(char));
186   for (i = 0; i < len - 1; i++)
187     if (name[i] == '/')
188       last_slash = i + 1;
189   if (last_slash > 0)
190     memcpy(dirname, name, last_slash);
191   return(dirname);
192 }
193 
194 
file_to_string(const char * filename)195 char *file_to_string(const char *filename)
196 {
197   FILE *file;
198   long size;
199   char *content = NULL;
200   file = fopen(filename, "r");
201   if (!file) return(NULL);
202   fseek(file, 0, SEEK_END);
203   size = ftell(file);
204   if (size > 0)
205     {
206       size_t bytes;
207       rewind(file);
208       content = (char *)calloc(size + 1, sizeof(char));
209       bytes = fread(content, sizeof(char), size, file);
210       if (bytes == 0)
211 	fprintf(stderr, "file->string read error");
212     }
213   fclose(file);
214   return(content);
215 }
216 
217 
vstr(const char * format,va_list ap)218 char *vstr(const char *format, va_list ap)
219 {
220   char *buf;
221 #ifndef _MSC_VER
222   if (vasprintf(&buf, format, ap) == -1)
223     return(NULL);
224 #else
225   int len;
226   len = mus_strlen(format) + PRINT_BUFFER_SIZE;
227   buf = (char *)calloc(len, sizeof(char));
228   vsnprintf(buf, len, format, ap);
229 #endif
230   return(buf);
231 }
232 
233 
disk_has_space(mus_long_t bytes,const char * filename)234 disk_space_t disk_has_space(mus_long_t bytes, const char *filename)
235 {
236   mus_long_t kfree, kneeded;
237   kfree = disk_kspace(filename);
238   if (kfree < 0)
239     {
240       snd_error("can't access %s: %s", filename, snd_io_strerror());
241       return(NO_DISK_SPACE);
242     }
243   kneeded = bytes >> 10;
244   if (kfree < kneeded)
245     {
246       snd_error("not enough space left on disk: only %" print_mus_long " kbytes available", kfree);
247       return(NOT_ENOUGH_DISK_SPACE);
248     }
249   return(DISK_SPACE_OK);
250 }
251 
252 
prettyf(double num,int tens)253 char *prettyf(double num, int tens)
254 {
255   /* try to prettify float display -- if tens <= 0, return int */
256   static char prtbuf[256];
257 
258   if (tens <= 0)
259     snprintf(prtbuf, 256, "%d", (int)snd_round(num));
260   else
261     {
262       int i, len;
263       snprintf(prtbuf, 256, "%.*f", tens, num); /* %f assumes double arg */
264       /* look for trailing 0's beyond the ddd.0 case */
265       len = strlen(prtbuf);
266       for (i = len - 1; (i > 0) && (prtbuf[i] == '0') && (prtbuf[i - 1] != '.'); i--)
267 	prtbuf[i] = '\0';
268     }
269   return(mus_strdup(prtbuf));
270 }
271 
272 
get_tmpdir(void)273 static char *get_tmpdir(void)
274 {
275   char *tmpdir;
276   int len;
277   tmpdir = mus_strdup(getenv("TMPDIR"));
278   if ((!tmpdir) && (MUS_DEFAULT_TEMP_DIR)) tmpdir = mus_strdup(MUS_DEFAULT_TEMP_DIR);
279 #ifdef P_tmpdir
280   if (!tmpdir) tmpdir = mus_strdup(P_tmpdir); /* /usr/include/stdio.h */
281 #else
282   if (!tmpdir) return(mus_strdup("/tmp"));
283 #endif
284   if (!tmpdir) return(mus_strdup("."));
285   len = strlen(tmpdir);
286   if (tmpdir[len - 1] == '/') tmpdir[len - 1] = 0; /* this is what forces us to copy the string above (Sun segfaults otherwise) */
287   return(tmpdir);
288 }
289 
290 
291 static int sect_ctr = 0;
292 
shorter_tempnam(const char * udir,const char * prefix)293 char *shorter_tempnam(const char *udir, const char *prefix)
294 {
295   /* tempnam turns out names that are inconveniently long (in this case the filename is user-visible) */
296   char *str, *tmpdir = NULL;
297   str = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
298   if ((!udir) || (mus_strlen(udir) == 0))
299     tmpdir = get_tmpdir(); /* incoming dir could be "" */
300   else tmpdir = mus_strdup(udir);
301   if (tmpdir)
302     {
303       snprintf(str, PRINT_BUFFER_SIZE, "%s%s%s%d_%d.snd",
304 	       tmpdir,
305 	       (tmpdir[strlen(tmpdir) - 1] == '/') ? "" : "/",
306 	       (prefix) ? prefix : "snd_",
307 	       (int)getpid(),
308 	       sect_ctr++);
309       free(tmpdir);
310     }
311   else snprintf(str, PRINT_BUFFER_SIZE, "%s%d_%d.snd",
312 		(prefix) ? prefix : "snd_",
313 		(int)getpid(),
314 		sect_ctr++);
315   tmpdir = mus_strdup(str);
316   free(str);
317   return(tmpdir);
318 }
319 
320 
snd_tempnam(void)321 char *snd_tempnam(void)
322 {
323   char *udir;
324   udir = temp_dir(ss);
325   if ((udir) && (*udir))
326     return(shorter_tempnam(udir, "snd_"));
327   return(shorter_tempnam(NULL, "snd_"));
328 }
329 
330 
331 #if MUS_PORTAUDIO
332 #include <portaudio.h>
333 #endif
334 
snd_exit(int val)335 void snd_exit(int val)
336 {
337 #if MUS_PORTAUDIO
338   Pa_Terminate();
339 #endif
340   exit(val);
341 }
342 
343 
344 /* currently this is only used by the test suite (snd-test.scm)
345  */
346 #if HAVE_SCHEME
347 #define S_file_to_string "file->string"
348 
g_file_to_string(Xen name)349 static Xen g_file_to_string(Xen name)
350 {
351   char *contents;
352   Xen val = Xen_false;
353   Xen_check_type(Xen_is_string(name), name, 1, S_file_to_string, "a string");
354   contents = file_to_string(Xen_string_to_C_string(name));
355   val = C_string_to_Xen_string(contents);
356   free(contents);
357   return(val);
358 }
359 #endif
360 
361 
362 #if HAVE_SCHEME
Xen_wrap_1_arg(g_file_to_string_w,g_file_to_string)363   Xen_wrap_1_arg(g_file_to_string_w, g_file_to_string)
364 #endif
365 
366 void g_init_utils(void)
367 {
368 #if HAVE_SCHEME
369   Xen_define_typed_procedure(S_file_to_string, g_file_to_string_w, 1, 0, 0, "file contents as string",
370 			     s7_make_circular_signature(s7, 0, 1, s7_make_symbol(s7, "string?")));
371 #endif
372 }
373