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