#if (defined(__GNUC__)) && (!(defined(__cplusplus))) #define _GNU_SOURCE /* this is needed to get the vasprintf declaration */ #endif #include "snd.h" int snd_round(double x) /* needs to be double here (not mus_float_t) for x axis calcs */ { int i; i = (int)x; if ((x - i) > 0.5) return(i + 1); return(i); } mus_long_t snd_round_mus_long_t(double x) { mus_long_t i; i = (mus_long_t)x; if ((x - i) > 0.5) return(i + 1); return(i); } mus_long_t snd_abs_mus_long_t(mus_long_t val) { /* div is also limited to int */ return((val < 0) ? -val : val); } #define POW2_SIZE 31 static int ipow2s[POW2_SIZE] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824}; int snd_int_pow2(int n) { return(ipow2s[n]); } mus_long_t snd_mus_long_t_pow2(int n) { if ((n < 0) || (n > 46)) return(0); if (n < POW2_SIZE) return((mus_long_t)ipow2s[n]); return((mus_long_t)ipow2s[16] * (mus_long_t)ipow2s[n - 16]); /* can't store an array as above -- compiler complaints */ } int snd_to_int_pow2(int n) { /* round up to next power of 2 */ int i; for (i = 0; i < POW2_SIZE; i++) if (ipow2s[i] >= n) return(ipow2s[i]); return(0); } int snd_int_log2(int n) { /* round down */ int i; for (i = 1; i < POW2_SIZE; i++) if (ipow2s[i] > n) return(i - 1); return(0); } #define MAX_FLOAT_DIFF_FOR_EQUAL 0.0000001 bool snd_feq(mus_float_t val1, mus_float_t val2) { /* if some float can be affected by a widget, we can easily get float inaccuracies that confuse "==" (in gtk in particular) */ if (val1 == val2) return(true); if (fabs(val1 - val2) < MAX_FLOAT_DIFF_FOR_EQUAL) return(true); return(false); } #if !(defined(__GNUC__) && (!(defined(__cplusplus)))) mus_float_t in_dB(mus_float_t min_dB, mus_float_t lin_dB, mus_float_t val) { return((val <= lin_dB) ? min_dB : (20.0 * log10(val))); } #endif #define TIME_STR_SIZE 64 static char time_buf[TIME_STR_SIZE]; char *snd_local_time(void) { time_t ts; time(&ts); strftime(time_buf, TIME_STR_SIZE, STRFTIME_FORMAT, localtime(&ts)); return(time_buf); } char *snd_strftime(const char *format, time_t date) { strftime(time_buf, TIME_STR_SIZE, format, localtime(&date)); return(time_buf); } char *snd_io_strerror(void) /* "snd_strerror" is exported by ALSA! */ { if (ss->local_errno != 0) return(strerror(ss->local_errno)); if (errno != 0) return(strerror(errno)); return(NULL); } char *snd_open_strerror(void) { if (ss->local_open_errno != 0) return(strerror(ss->local_open_errno)); return(snd_io_strerror()); } char *string_to_colon(char *val) { char *up_to_colon; int i, len; up_to_colon = (char *)calloc(strlen(val) + 1, sizeof(char)); len = strlen(val); for (i = 0; i < len; i++) { if ((val[i] == ':') || (val[i] == ' ')) { up_to_colon[i] = 0; return(up_to_colon); } up_to_colon[i] = val[i]; } return(up_to_colon); } char *filename_without_directory(const char *name) { /* since I don't want to mess with freeing these guys, I'll just return a pointer into the name */ int i, len, last_slash; last_slash = 0; len = strlen(name); for (i = 0; i < len - 1; i++) if (name[i] == '/') last_slash = i + 1; return((char *)(name + last_slash)); } char *just_filename(char *name) { char *nodir; int i, len; nodir = mus_strdup(filename_without_directory(name)); len = strlen(nodir); for (i = 0; i < len; i++) if (nodir[i] == '.') { nodir[i] = '\0'; break; } return(nodir); } char *just_directory(const char *name) { int i, len, last_slash = 0; char *dirname; len = strlen(name); dirname = (char *)calloc(len + 1, sizeof(char)); for (i = 0; i < len - 1; i++) if (name[i] == '/') last_slash = i + 1; if (last_slash > 0) memcpy(dirname, name, last_slash); return(dirname); } char *file_to_string(const char *filename) { FILE *file; long size; char *content = NULL; file = fopen(filename, "r"); if (!file) return(NULL); fseek(file, 0, SEEK_END); size = ftell(file); if (size > 0) { size_t bytes; rewind(file); content = (char *)calloc(size + 1, sizeof(char)); bytes = fread(content, sizeof(char), size, file); if (bytes == 0) fprintf(stderr, "file->string read error"); } fclose(file); return(content); } char *vstr(const char *format, va_list ap) { char *buf; #ifndef _MSC_VER if (vasprintf(&buf, format, ap) == -1) return(NULL); #else int len; len = mus_strlen(format) + PRINT_BUFFER_SIZE; buf = (char *)calloc(len, sizeof(char)); vsnprintf(buf, len, format, ap); #endif return(buf); } disk_space_t disk_has_space(mus_long_t bytes, const char *filename) { mus_long_t kfree, kneeded; kfree = disk_kspace(filename); if (kfree < 0) { snd_error("can't access %s: %s", filename, snd_io_strerror()); return(NO_DISK_SPACE); } kneeded = bytes >> 10; if (kfree < kneeded) { snd_error("not enough space left on disk: only %" print_mus_long " kbytes available", kfree); return(NOT_ENOUGH_DISK_SPACE); } return(DISK_SPACE_OK); } char *prettyf(double num, int tens) { /* try to prettify float display -- if tens <= 0, return int */ static char prtbuf[256]; if (tens <= 0) snprintf(prtbuf, 256, "%d", (int)snd_round(num)); else { int i, len; snprintf(prtbuf, 256, "%.*f", tens, num); /* %f assumes double arg */ /* look for trailing 0's beyond the ddd.0 case */ len = strlen(prtbuf); for (i = len - 1; (i > 0) && (prtbuf[i] == '0') && (prtbuf[i - 1] != '.'); i--) prtbuf[i] = '\0'; } return(mus_strdup(prtbuf)); } static char *get_tmpdir(void) { char *tmpdir; int len; tmpdir = mus_strdup(getenv("TMPDIR")); if ((!tmpdir) && (MUS_DEFAULT_TEMP_DIR)) tmpdir = mus_strdup(MUS_DEFAULT_TEMP_DIR); #ifdef P_tmpdir if (!tmpdir) tmpdir = mus_strdup(P_tmpdir); /* /usr/include/stdio.h */ #else if (!tmpdir) return(mus_strdup("/tmp")); #endif if (!tmpdir) return(mus_strdup(".")); len = strlen(tmpdir); if (tmpdir[len - 1] == '/') tmpdir[len - 1] = 0; /* this is what forces us to copy the string above (Sun segfaults otherwise) */ return(tmpdir); } static int sect_ctr = 0; char *shorter_tempnam(const char *udir, const char *prefix) { /* tempnam turns out names that are inconveniently long (in this case the filename is user-visible) */ char *str, *tmpdir = NULL; str = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char)); if ((!udir) || (mus_strlen(udir) == 0)) tmpdir = get_tmpdir(); /* incoming dir could be "" */ else tmpdir = mus_strdup(udir); if (tmpdir) { snprintf(str, PRINT_BUFFER_SIZE, "%s%s%s%d_%d.snd", tmpdir, (tmpdir[strlen(tmpdir) - 1] == '/') ? "" : "/", (prefix) ? prefix : "snd_", (int)getpid(), sect_ctr++); free(tmpdir); } else snprintf(str, PRINT_BUFFER_SIZE, "%s%d_%d.snd", (prefix) ? prefix : "snd_", (int)getpid(), sect_ctr++); tmpdir = mus_strdup(str); free(str); return(tmpdir); } char *snd_tempnam(void) { char *udir; udir = temp_dir(ss); if ((udir) && (*udir)) return(shorter_tempnam(udir, "snd_")); return(shorter_tempnam(NULL, "snd_")); } #if MUS_PORTAUDIO #include #endif void snd_exit(int val) { #if MUS_PORTAUDIO Pa_Terminate(); #endif exit(val); } /* currently this is only used by the test suite (snd-test.scm) */ #if HAVE_SCHEME #define S_file_to_string "file->string" static Xen g_file_to_string(Xen name) { char *contents; Xen val = Xen_false; Xen_check_type(Xen_is_string(name), name, 1, S_file_to_string, "a string"); contents = file_to_string(Xen_string_to_C_string(name)); val = C_string_to_Xen_string(contents); free(contents); return(val); } #endif #if HAVE_SCHEME Xen_wrap_1_arg(g_file_to_string_w, g_file_to_string) #endif void g_init_utils(void) { #if HAVE_SCHEME Xen_define_typed_procedure(S_file_to_string, g_file_to_string_w, 1, 0, 0, "file contents as string", s7_make_circular_signature(s7, 0, 1, s7_make_symbol(s7, "string?"))); #endif }