You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1282 lines
51KB

  1. /* Tie sndlib into Xen */
  2. #include "mus-config.h"
  3. #if USE_SND
  4. #include "snd.h"
  5. #else
  6. #if HAVE_RUBY
  7. #define PROC_FALSE "false"
  8. #define PROC_TRUE "true"
  9. #endif
  10. #if HAVE_SCHEME || HAVE_FORTH
  11. #define PROC_FALSE "#f"
  12. #define PROC_TRUE "#t"
  13. #endif
  14. #endif
  15. #include <stddef.h>
  16. #include <math.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <sys/types.h>
  20. #include <string.h>
  21. #include <errno.h>
  22. #ifdef _MSC_VER
  23. #pragma warning(disable: 4244)
  24. #endif
  25. #include "_sndlib.h"
  26. #include "sndlib-strings.h"
  27. #include "vct.h"
  28. #include "clm.h"
  29. #include "sndlib2xen.h"
  30. #include "clm2xen.h"
  31. #ifndef S_set
  32. #if HAVE_RUBY
  33. #define S_set "set_"
  34. #endif
  35. #if HAVE_SCHEME
  36. #define S_set "set! "
  37. #endif
  38. #if HAVE_FORTH
  39. #define S_set "set-"
  40. #endif
  41. #endif
  42. /* originally I tried to simplify C GC by using global static strings that were
  43. * freed whenever the associated function was called again, on the assumption
  44. * that the preceding value was now unused. In a multithread context, that
  45. * assumption is false, so I didn't use code like this:
  46. *
  47. * static char *tmpstr = NULL;
  48. *
  49. * static char *local_mus_expand_filename(char *name)
  50. * {
  51. * if (tmpstr) {free(tmpstr); tmpstr = NULL;}
  52. * tmpstr = mus_expand_filename(name);
  53. * return(tmpstr);
  54. * }
  55. */
  56. static Xen g_mus_sound_loop_info(Xen gfilename)
  57. {
  58. #define H_mus_sound_loop_info "(" S_mus_sound_loop_info " filename): synth loop info for sound as a list: (start1 \
  59. end1 start2 end2 base-note base-detune mode1 mode2)"
  60. int *res;
  61. Xen sres = Xen_empty_list;
  62. char *str = NULL;
  63. Xen_check_type(Xen_is_string(gfilename), gfilename, 1, S_mus_sound_loop_info, "a string");
  64. res = mus_sound_loop_info(str = mus_expand_filename(Xen_string_to_C_string(gfilename)));
  65. if (str) free(str);
  66. if (res)
  67. {
  68. sres = Xen_list_8(C_int_to_Xen_integer(res[0]), C_int_to_Xen_integer(res[1]), C_int_to_Xen_integer(res[2]),
  69. C_int_to_Xen_integer(res[3]), C_int_to_Xen_integer(res[4]), C_int_to_Xen_integer(res[5]),
  70. C_int_to_Xen_integer(res[6]), C_int_to_Xen_integer(res[7]));
  71. free(res);
  72. }
  73. return(sres);
  74. }
  75. static Xen g_mus_sound_mark_info(Xen gfilename)
  76. {
  77. #define H_mus_sound_mark_info "(" S_mus_sound_mark_info " filename): aifc header mark info as a list of lists: ((id pos)...)"
  78. int *mark_ids, *mark_positions;
  79. int marks = 0;
  80. Xen sres = Xen_empty_list;
  81. char *str = NULL;
  82. Xen_check_type(Xen_is_string(gfilename), gfilename, 1, S_mus_sound_mark_info, "a string");
  83. marks = mus_sound_mark_info(str = mus_expand_filename(Xen_string_to_C_string(gfilename)), &mark_ids, &mark_positions);
  84. if (str) free(str);
  85. if (marks > 0)
  86. {
  87. int i;
  88. for (i = 0; i < marks; i++)
  89. sres = Xen_cons(Xen_list_2(C_int_to_Xen_integer(mark_ids[i]),
  90. C_int_to_Xen_integer(mark_positions[i])),
  91. sres);
  92. }
  93. return(sres);
  94. }
  95. static Xen gmus_sound(const char *caller, int (*func)(const char *file), Xen gfilename)
  96. {
  97. char *str = NULL;
  98. Xen result;
  99. Xen_check_type(Xen_is_string(gfilename), gfilename, 1, caller, "a string");
  100. str = mus_expand_filename(Xen_string_to_C_string(gfilename));
  101. result = C_int_to_Xen_integer((*func)(str));
  102. if (str) free(str);
  103. return(result);
  104. }
  105. static Xen gmus_sound_set(const char *caller, int (*func)(const char *file, int newval), Xen gfilename, Xen val)
  106. {
  107. char *str = NULL;
  108. Xen result;
  109. Xen_check_type(Xen_is_string(gfilename), gfilename, 1, caller, "a string");
  110. Xen_check_type(Xen_is_integer(val), val, 2, caller, "an integer");
  111. str = mus_expand_filename(Xen_string_to_C_string(gfilename));
  112. result = C_int_to_Xen_integer((*func)(str, Xen_integer_to_C_int(val)));
  113. if (str) free(str);
  114. return(result);
  115. }
  116. static Xen glmus_sound(const char *caller, mus_long_t (*func)(const char *file), Xen gfilename)
  117. {
  118. char *str = NULL;
  119. Xen result;
  120. Xen_check_type(Xen_is_string(gfilename), gfilename, 1, caller, "a string");
  121. str = mus_expand_filename(Xen_string_to_C_string(gfilename));
  122. result = C_llong_to_Xen_llong((*func)(str));
  123. if (str) free(str);
  124. return(result);
  125. }
  126. static Xen glmus_sound_set(const char *caller, int (*func)(const char *file, mus_long_t newval), Xen gfilename, Xen val)
  127. {
  128. char *str = NULL;
  129. Xen result;
  130. Xen_check_type(Xen_is_string(gfilename), gfilename, 1, caller, "a string");
  131. Xen_check_type(Xen_is_number(val), val, 2, caller, "a number");
  132. str = mus_expand_filename(Xen_string_to_C_string(gfilename));
  133. result = C_llong_to_Xen_llong((*func)(str, Xen_llong_to_C_llong(val)));
  134. if (str) free(str);
  135. return(result);
  136. }
  137. static Xen g_mus_sound_samples(Xen filename)
  138. {
  139. #define H_mus_sound_samples "(" S_mus_sound_samples " filename): samples (framples * channels) in sound file"
  140. return(glmus_sound(S_mus_sound_samples, mus_sound_samples, filename));
  141. }
  142. static Xen g_mus_sound_set_samples(Xen filename, Xen val)
  143. {
  144. return(glmus_sound_set(S_set S_mus_sound_samples, mus_sound_set_samples, filename, val));
  145. }
  146. Xen g_mus_sound_framples(Xen filename)
  147. {
  148. #define H_mus_sound_framples "(" S_mus_sound_framples " filename): framples (samples / channel) in sound file"
  149. return(glmus_sound(S_mus_sound_framples, mus_sound_framples, filename));
  150. }
  151. static Xen g_mus_sound_datum_size(Xen filename)
  152. {
  153. #define H_mus_sound_datum_size "(" S_mus_sound_datum_size " filename): bytes per sample used by the data in sound file (sample type dependent)"
  154. return(gmus_sound(S_mus_sound_datum_size, mus_sound_datum_size, filename));
  155. }
  156. static Xen g_mus_sound_data_location(Xen filename)
  157. {
  158. #define H_mus_sound_data_location "(" S_mus_sound_data_location " filename): location (in bytes) of first sample of sound data"
  159. return(glmus_sound(S_mus_sound_data_location, mus_sound_data_location, filename));
  160. }
  161. static Xen g_mus_sound_set_data_location(Xen filename, Xen val)
  162. {
  163. return(glmus_sound_set(S_set S_mus_sound_data_location, mus_sound_set_data_location, filename, val));
  164. }
  165. Xen g_mus_sound_chans(Xen filename)
  166. {
  167. #define H_mus_sound_chans "(" S_mus_sound_chans " filename): channels of data in sound file"
  168. return(gmus_sound(S_mus_sound_chans, mus_sound_chans, filename));
  169. }
  170. static Xen g_mus_sound_set_chans(Xen filename, Xen val)
  171. {
  172. return(gmus_sound_set(S_set S_mus_sound_chans, mus_sound_set_chans, filename, val));
  173. }
  174. Xen g_mus_sound_srate(Xen filename)
  175. {
  176. #define H_mus_sound_srate "(" S_mus_sound_srate " filename): sampling rate of sound file"
  177. return(gmus_sound(S_mus_sound_srate, mus_sound_srate, filename));
  178. }
  179. static Xen g_mus_sound_set_srate(Xen filename, Xen val)
  180. {
  181. return(gmus_sound_set(S_set S_mus_sound_srate, mus_sound_set_srate, filename, val));
  182. }
  183. static Xen g_mus_sound_header_type(Xen filename)
  184. {
  185. #define H_mus_sound_header_type "(" S_mus_sound_header_type " filename): header type (e.g. " S_mus_aifc ") of sound file"
  186. char *str = NULL;
  187. Xen result;
  188. Xen_check_type(Xen_is_string(filename), filename, 1, S_mus_sound_header_type, "a string");
  189. str = mus_expand_filename(Xen_string_to_C_string(filename));
  190. result = C_int_to_Xen_integer((int)mus_sound_header_type(str));
  191. if (str) free(str);
  192. return(result);
  193. }
  194. static Xen g_mus_sound_set_header_type(Xen filename, Xen val)
  195. {
  196. char *str = NULL;
  197. Xen result;
  198. Xen_check_type(Xen_is_string(filename), filename, 1, S_set S_mus_sound_header_type, "a string");
  199. Xen_check_type(Xen_is_integer(val), val, 2, S_set S_mus_sound_header_type, "an integer");
  200. str = mus_expand_filename(Xen_string_to_C_string(filename));
  201. result = C_int_to_Xen_integer((int)mus_sound_set_header_type(str, (mus_header_t)Xen_integer_to_C_int(val)));
  202. if (str) free(str);
  203. return(result);
  204. }
  205. static Xen g_mus_sound_sample_type(Xen filename)
  206. {
  207. #define H_mus_sound_sample_type "(" S_mus_sound_sample_type " filename): sample type (e.g. " S_mus_bshort ") of data in sound file"
  208. char *str = NULL;
  209. Xen result;
  210. Xen_check_type(Xen_is_string(filename), filename, 1, S_mus_sound_sample_type, "a string");
  211. str = mus_expand_filename(Xen_string_to_C_string(filename));
  212. result = C_int_to_Xen_integer((int)mus_sound_sample_type(str));
  213. if (str) free(str);
  214. return(result);
  215. }
  216. static Xen g_mus_sound_set_sample_type(Xen filename, Xen val)
  217. {
  218. char *str = NULL;
  219. Xen result;
  220. Xen_check_type(Xen_is_string(filename), filename, 1, S_set S_mus_sound_sample_type, "a string");
  221. Xen_check_type(Xen_is_integer(val), val, 2, S_set S_mus_sound_sample_type, "an integer");
  222. str = mus_expand_filename(Xen_string_to_C_string(filename));
  223. result = C_int_to_Xen_integer((int)mus_sound_set_sample_type(str, (mus_sample_t)Xen_integer_to_C_int(val)));
  224. if (str) free(str);
  225. return(result);
  226. }
  227. static Xen g_mus_sound_length(Xen filename)
  228. {
  229. #define H_mus_sound_length "(" S_mus_sound_length " filename): sound file length in bytes"
  230. return(glmus_sound(S_mus_sound_length, mus_sound_length, filename));
  231. }
  232. static Xen g_mus_sound_type_specifier(Xen filename)
  233. {
  234. #define H_mus_sound_type_specifier "(" S_mus_sound_type_specifier " filename): original sound file header type identifier (e.g. 0x2e736e64)"
  235. return(gmus_sound(S_mus_sound_type_specifier, mus_sound_type_specifier, filename));
  236. }
  237. static Xen g_mus_sound_forget(Xen filename)
  238. {
  239. #define H_mus_sound_forget "(" S_mus_sound_forget " filename): remove 'filename' from sound cache. If you create, then later \
  240. delete a sound file, " S_mus_sound_forget " can be used to clear it from sndlib's cache of sound files"
  241. return(gmus_sound(S_mus_sound_forget, mus_sound_forget, filename));
  242. }
  243. static Xen g_mus_sound_prune(void)
  244. {
  245. #define H_mus_sound_prune "(" S_mus_sound_prune "): remove all defunct entries from sndlib's sound file cache."
  246. return(C_int_to_Xen_integer(mus_sound_prune()));
  247. }
  248. static Xen g_mus_sound_comment(Xen gfilename)
  249. {
  250. #define H_mus_sound_comment "(" S_mus_sound_comment " filename): comment (a string) found in sound file's header"
  251. char *res = NULL, *str = NULL;
  252. Xen newstr;
  253. Xen_check_type(Xen_is_string(gfilename), gfilename, 1, S_mus_sound_comment, "a string");
  254. res = mus_sound_comment(str = mus_expand_filename(Xen_string_to_C_string(gfilename)));
  255. if (str) free(str);
  256. newstr = C_string_to_Xen_string(res);
  257. if (res) free(res);
  258. return(newstr);
  259. }
  260. static Xen g_mus_sound_write_date(Xen filename)
  261. {
  262. char *str = NULL;
  263. Xen result;
  264. #define H_mus_sound_write_date "(" S_mus_sound_write_date " filename): write date of sound file"
  265. Xen_check_type(Xen_is_string(filename), filename, 1, S_mus_sound_write_date, "a string");
  266. str = mus_expand_filename(Xen_string_to_C_string(filename));
  267. result = C_ulong_to_Xen_ulong((unsigned long)mus_sound_write_date(str)); /* actually time_t */
  268. if (str) free(str);
  269. return(result);
  270. }
  271. static Xen g_mus_header_writable(Xen head, Xen data)
  272. {
  273. #define H_mus_header_writable "(" S_mus_header_writable " header-type sample-type) returns " PROC_TRUE " if the header can handle the sample type"
  274. Xen_check_type(Xen_is_integer(head), head, 1, S_mus_header_writable, "a header type");
  275. Xen_check_type(Xen_is_integer(data), data, 2, S_mus_header_writable, "a sample type");
  276. return(C_bool_to_Xen_boolean(mus_header_writable((mus_header_t)Xen_integer_to_C_int(head), (mus_sample_t)Xen_integer_to_C_int(data))));
  277. }
  278. static Xen g_mus_header_raw_defaults(void)
  279. {
  280. #define H_mus_header_raw_defaults "(" S_mus_header_raw_defaults "): returns list '(srate chans sample-type) of current raw sound default attributes"
  281. int srate, chans;
  282. mus_sample_t sample_type;
  283. mus_header_raw_defaults(&srate, &chans, &sample_type);
  284. return(Xen_list_3(C_int_to_Xen_integer(srate),
  285. C_int_to_Xen_integer(chans),
  286. C_int_to_Xen_integer((int)sample_type)));
  287. }
  288. static Xen g_mus_header_set_raw_defaults(Xen lst)
  289. {
  290. Xen_check_type((Xen_is_list(lst)) && (Xen_list_length(lst) == 3), lst, 1, S_mus_header_raw_defaults, "a list: '(srate chans sample-type)");
  291. Xen_check_type(Xen_is_integer(Xen_car(lst)), Xen_car(lst), 1, S_mus_header_raw_defaults, "an integer = srate");
  292. Xen_check_type(Xen_is_integer(Xen_cadr(lst)), Xen_cadr(lst), 2, S_mus_header_raw_defaults, "an integer = chans");
  293. Xen_check_type(Xen_is_integer(Xen_caddr(lst)), Xen_caddr(lst), 3, S_mus_header_raw_defaults, "an integer = sample-type");
  294. mus_header_set_raw_defaults(Xen_integer_to_C_int(Xen_car(lst)),
  295. Xen_integer_to_C_int(Xen_cadr(lst)),
  296. (mus_sample_t)Xen_integer_to_C_int(Xen_caddr(lst)));
  297. return(lst);
  298. }
  299. static Xen g_mus_header_type_name(Xen type)
  300. {
  301. #define H_mus_header_type_name "(" S_mus_header_type_name " type): header type (e.g. " S_mus_aiff ") as a string"
  302. Xen_check_type(Xen_is_integer(type), type, 1, S_mus_header_type_name, "an integer (header-type id)");
  303. return(C_string_to_Xen_string(mus_header_type_name((mus_header_t)Xen_integer_to_C_int(type))));
  304. }
  305. static Xen g_mus_header_type_to_string(Xen type)
  306. {
  307. #define H_mus_header_type_to_string "(" S_mus_header_type_to_string " type): header type (e.g. " S_mus_aiff ") as a string"
  308. Xen_check_type(Xen_is_integer(type), type, 1, S_mus_header_type_to_string, "an integer (header-type id)");
  309. return(C_string_to_Xen_string(mus_header_type_to_string((mus_header_t)Xen_integer_to_C_int(type))));
  310. }
  311. static Xen g_mus_sample_type_name(Xen samp_type)
  312. {
  313. #define H_mus_sample_type_name "(" S_mus_sample_type_name " samp_type): sample type (e.g. " S_mus_bshort ") as a string"
  314. Xen_check_type(Xen_is_integer(samp_type), samp_type, 1, S_mus_sample_type_name, "an integer (sample-type id)");
  315. return(C_string_to_Xen_string(mus_sample_type_name((mus_sample_t)Xen_integer_to_C_int(samp_type))));
  316. }
  317. static Xen g_mus_sample_type_to_string(Xen samp_type)
  318. {
  319. #define H_mus_sample_type_to_string "(" S_mus_sample_type_to_string " samp_type): sample type (e.g. " S_mus_bshort ") as a string"
  320. Xen_check_type(Xen_is_integer(samp_type), samp_type, 1, S_mus_sample_type_to_string, "an integer (sample-type id)");
  321. return(C_string_to_Xen_string(mus_sample_type_to_string((mus_sample_t)Xen_integer_to_C_int(samp_type))));
  322. }
  323. static Xen g_mus_bytes_per_sample(Xen samp_type)
  324. {
  325. #define H_mus_bytes_per_sample "(" S_mus_bytes_per_sample " sample-type): number of bytes per sample in \
  326. sample-type (e.g. " S_mus_bshort " = 2)"
  327. Xen_check_type(Xen_is_integer(samp_type), samp_type, 1, S_mus_bytes_per_sample, "an integer (sample-type id)");
  328. return(C_int_to_Xen_integer(mus_bytes_per_sample((mus_sample_t)Xen_integer_to_C_int(samp_type))));
  329. }
  330. static Xen g_mus_sound_duration(Xen gfilename)
  331. {
  332. #define H_mus_sound_duration "(" S_mus_sound_duration " filename): duration (in seconds) of sound file"
  333. float res;
  334. char *str = NULL;
  335. Xen_check_type(Xen_is_string(gfilename), gfilename, 1, S_mus_sound_duration, "a string");
  336. res = mus_sound_duration(str = mus_expand_filename(Xen_string_to_C_string(gfilename)));
  337. if (str) free(str);
  338. return(C_double_to_Xen_real(res));
  339. }
  340. static Xen g_mus_oss_set_buffers(Xen num, Xen size)
  341. {
  342. #define H_mus_oss_set_buffers "(" S_mus_oss_set_buffers " num size): set Linux OSS 'fragment' number and size. \
  343. If Snd's controls seem sluggish, try (" S_mus_oss_set_buffers " 4 12) or even (" S_mus_oss_set_buffers " 2 12). \
  344. This reduces the on-card buffering, but may introduce clicks."
  345. #if (HAVE_OSS || HAVE_ALSA)
  346. Xen_check_type(Xen_is_integer(num), num, 1, S_mus_oss_set_buffers, "an integer");
  347. Xen_check_type(Xen_is_integer(size), size, 2, S_mus_oss_set_buffers, "an integer");
  348. mus_oss_set_buffers(Xen_integer_to_C_int(num),
  349. Xen_integer_to_C_int(size));
  350. #endif
  351. return(Xen_false);
  352. }
  353. static Xen g_mus_alsa_buffers(void)
  354. {
  355. #define H_mus_alsa_buffers "(" S_mus_alsa_buffers "): current number of ALSA periods."
  356. #if HAVE_ALSA
  357. return(C_int_to_Xen_integer(mus_alsa_buffers()));
  358. #endif
  359. return(Xen_false);
  360. }
  361. static Xen g_mus_alsa_set_buffers(Xen val)
  362. {
  363. Xen_check_type(Xen_is_integer(val), val, 1, S_set S_mus_alsa_buffers, "an integer");
  364. #if HAVE_ALSA
  365. return(C_int_to_Xen_integer(mus_alsa_set_buffers(Xen_integer_to_C_int(val))));
  366. #endif
  367. return(Xen_false);
  368. }
  369. static Xen g_mus_alsa_buffer_size(void)
  370. {
  371. #define H_mus_alsa_buffer_size "(" S_mus_alsa_buffer_size "): current size of ALSA buffers."
  372. #if HAVE_ALSA
  373. return(C_int_to_Xen_integer(mus_alsa_buffer_size()));
  374. #endif
  375. return(Xen_false);
  376. }
  377. static Xen g_mus_alsa_set_buffer_size(Xen val)
  378. {
  379. Xen_check_type(Xen_is_integer(val), val, 1, S_set S_mus_alsa_buffer_size, "an integer");
  380. #if HAVE_ALSA
  381. return(C_int_to_Xen_integer(mus_alsa_set_buffer_size(Xen_integer_to_C_int(val))));
  382. #endif
  383. return(Xen_false);
  384. }
  385. static Xen g_mus_alsa_device(void)
  386. {
  387. #define H_mus_alsa_device "(" S_mus_alsa_device "): current ALSA device."
  388. #if HAVE_ALSA
  389. return(C_string_to_Xen_string(mus_alsa_device()));
  390. #endif
  391. return(Xen_false);
  392. }
  393. static Xen g_mus_alsa_set_device(Xen val)
  394. {
  395. Xen_check_type(Xen_is_string(val), val, 1, S_set S_mus_alsa_device, "a string (ALSA device name)");
  396. #if HAVE_ALSA
  397. return(C_string_to_Xen_string(mus_alsa_set_device(Xen_string_to_C_string(val))));
  398. #endif
  399. return(Xen_false);
  400. }
  401. static Xen g_mus_alsa_playback_device(void)
  402. {
  403. #define H_mus_alsa_playback_device "(" S_mus_alsa_playback_device "): current ALSA playback device."
  404. #if HAVE_ALSA
  405. return(C_string_to_Xen_string(mus_alsa_playback_device()));
  406. #endif
  407. return(Xen_false);
  408. }
  409. static Xen g_mus_alsa_set_playback_device(Xen val)
  410. {
  411. Xen_check_type(Xen_is_string(val), val, 1, S_set S_mus_alsa_playback_device, "a string (ALSA device name)");
  412. #if HAVE_ALSA
  413. return(C_string_to_Xen_string(mus_alsa_set_playback_device(Xen_string_to_C_string(val))));
  414. #endif
  415. return(Xen_false);
  416. }
  417. static Xen g_mus_alsa_capture_device(void)
  418. {
  419. #define H_mus_alsa_capture_device "(" S_mus_alsa_capture_device "): current ALSA capture device."
  420. #if HAVE_ALSA
  421. return(C_string_to_Xen_string(mus_alsa_capture_device()));
  422. #endif
  423. return(Xen_false);
  424. }
  425. static Xen g_mus_alsa_set_capture_device(Xen val)
  426. {
  427. Xen_check_type(Xen_is_string(val), val, 1, S_set S_mus_alsa_capture_device, "a string (ALSA device name)");
  428. #if HAVE_ALSA
  429. return(C_string_to_Xen_string(mus_alsa_set_capture_device(Xen_string_to_C_string(val))));
  430. #endif
  431. return(Xen_false);
  432. }
  433. static Xen g_mus_alsa_squelch_warning(void)
  434. {
  435. #define H_mus_alsa_squelch_warning "(" S_mus_alsa_squelch_warning "): whether to squelch ALSA srate mismatch warnings."
  436. #if HAVE_ALSA
  437. return(C_bool_to_Xen_boolean(mus_alsa_squelch_warning()));
  438. #endif
  439. return(Xen_false);
  440. }
  441. static Xen g_mus_alsa_set_squelch_warning(Xen val)
  442. {
  443. Xen_check_type(Xen_is_boolean(val), val, 1, S_set S_mus_alsa_squelch_warning, "a boolean");
  444. #if HAVE_ALSA
  445. return(C_bool_to_Xen_boolean(mus_alsa_set_squelch_warning(Xen_boolean_to_C_bool(val))));
  446. #endif
  447. return(Xen_false);
  448. }
  449. static Xen g_mus_sound_maxamp_exists(Xen file)
  450. {
  451. #define H_mus_sound_maxamp_exists "(" S_mus_sound_maxamp_exists " filename): " PROC_TRUE " if sound's maxamp data is available \
  452. in the sound cache; if it isn't, a call on " S_mus_sound_maxamp " has to open and read the data to get the maxamp."
  453. bool val;
  454. char *str = NULL;
  455. Xen_check_type(Xen_is_string(file), file, 1, S_mus_sound_maxamp_exists, "a string");
  456. val = mus_sound_maxamp_exists(str = mus_expand_filename(Xen_string_to_C_string(file)));
  457. if (str) free(str);
  458. return(C_bool_to_Xen_boolean(val));
  459. }
  460. Xen g_mus_sound_maxamp(Xen file)
  461. {
  462. #define H_mus_sound_maxamp "(" S_mus_sound_maxamp " filename): maxamps in sound (a list of paired amps (floats) and locations (samples))"
  463. int chans;
  464. char *filename;
  465. Xen res = Xen_empty_list;
  466. Xen_check_type(Xen_is_string(file), file, 1, S_mus_sound_maxamp, "a string");
  467. filename = mus_expand_filename(Xen_string_to_C_string(file));
  468. chans = mus_sound_chans(filename);
  469. if (chans > 0)
  470. {
  471. mus_long_t rtn;
  472. mus_float_t *vals;
  473. mus_long_t *times;
  474. vals = (mus_float_t *)calloc(chans, sizeof(mus_float_t));
  475. times = (mus_long_t *)calloc(chans, sizeof(mus_long_t));
  476. rtn = mus_sound_maxamps(filename, chans, vals, times);
  477. if (rtn != MUS_ERROR)
  478. {
  479. int i;
  480. for (i = chans - 1; i >= 0; i--)
  481. res = Xen_cons(C_llong_to_Xen_llong(times[i]), Xen_cons(C_double_to_Xen_real(vals[i]), res));
  482. }
  483. free(vals);
  484. free(times);
  485. if (filename) free(filename);
  486. }
  487. else
  488. {
  489. if (filename) free(filename);
  490. Xen_error(BAD_HEADER,
  491. Xen_list_1(C_string_to_Xen_string(S_mus_sound_maxamp ": chans <= 0")));
  492. }
  493. return(res);
  494. }
  495. static Xen g_mus_sound_set_maxamp(Xen file, Xen vals)
  496. {
  497. int chans;
  498. char *filename;
  499. Xen_check_type(Xen_is_string(file), file, 1, S_set S_mus_sound_maxamp, "a string");
  500. Xen_check_type(Xen_is_list(vals), vals, 2, S_set S_mus_sound_maxamp, "a list");
  501. filename = mus_expand_filename(Xen_string_to_C_string(file));
  502. chans = mus_sound_chans(filename);
  503. /* presumably any actual error here will be trapped via mus-error (raised in mus_header_read via read_sound_file_header),
  504. * so chans <= 0 is actually in the header?
  505. */
  506. if (chans > 0)
  507. {
  508. Xen lst;
  509. int i, j, len;
  510. mus_float_t *mvals;
  511. mus_long_t *times;
  512. len = Xen_list_length(vals);
  513. if (len < (chans * 2))
  514. Xen_wrong_type_arg_error(S_set S_mus_sound_maxamp, 2, vals, "max amp list length must = 2 * chans");
  515. if (len > chans * 2) len = chans * 2;
  516. mvals = (mus_float_t *)calloc(chans, sizeof(mus_float_t));
  517. times = (mus_long_t *)calloc(chans, sizeof(mus_long_t));
  518. for (i = 0, j = 0, lst = Xen_copy_arg(vals); i < len; i += 2, j++, lst = Xen_cddr(lst))
  519. {
  520. times[j] = Xen_llong_to_C_llong(Xen_car(lst));
  521. mvals[j] = Xen_real_to_C_double(Xen_cadr(lst));
  522. }
  523. fprintf(stderr, "set in g_mus_sound_set_maxamp\n");
  524. mus_sound_set_maxamps(filename, chans, mvals, times);
  525. free(mvals);
  526. free(times);
  527. if (filename) free(filename);
  528. }
  529. else
  530. {
  531. if (filename) free(filename);
  532. Xen_error(BAD_HEADER,
  533. Xen_list_1(C_string_to_Xen_string(S_set S_mus_sound_maxamp ": chans <= 0")));
  534. }
  535. return(vals);
  536. }
  537. #define S_mus_sound_preload "mus-sound-preload"
  538. static Xen g_mus_sound_preload(Xen file)
  539. {
  540. #define H_mus_sound_preload "(" S_mus_sound_preload " filename): save filename's data in memory (faster opens and so on)."
  541. char *str;
  542. Xen_check_type(Xen_is_string(file), file, 1, S_mus_sound_preload, "a string");
  543. str = mus_expand_filename(Xen_string_to_C_string(file));
  544. if (str)
  545. {
  546. int ifd;
  547. ifd = mus_sound_open_input(str);
  548. if (ifd != MUS_ERROR)
  549. {
  550. int i, chans;
  551. mus_float_t **bufs;
  552. mus_long_t framples;
  553. chans = mus_sound_chans(str);
  554. framples = mus_sound_framples(str) + 8; /* + 8 for readers that wander off the end */
  555. bufs = (mus_float_t **)malloc(chans * sizeof(mus_float_t *));
  556. for (i = 0; i < chans; i++)
  557. bufs[i] = (mus_float_t *)malloc(framples * sizeof(mus_float_t));
  558. mus_file_seek_frample(ifd, 0);
  559. mus_file_read_file(ifd, 0, chans, framples, bufs);
  560. mus_sound_set_saved_data(str, bufs);
  561. mus_sound_close_input(ifd);
  562. }
  563. free(str);
  564. }
  565. return(file);
  566. }
  567. /* global default clipping values */
  568. static Xen g_mus_clipping(void)
  569. {
  570. #define H_mus_clipping "(" S_mus_clipping "): whether sound data written to a file should be clipped"
  571. return(C_bool_to_Xen_boolean(mus_clipping()));
  572. }
  573. static Xen g_mus_set_clipping(Xen clipped)
  574. {
  575. Xen_check_type(Xen_is_boolean(clipped), clipped, 1, S_set S_mus_clipping, "a boolean");
  576. return(C_bool_to_Xen_boolean(mus_set_clipping(Xen_boolean_to_C_bool(clipped))));
  577. }
  578. /* file local clipping values */
  579. static Xen g_mus_file_clipping(Xen fd)
  580. {
  581. #define H_mus_file_clipping "(" S_mus_file_clipping " fd): whether sound data written to file 'fd' should be clipped"
  582. Xen_check_type(Xen_is_integer(fd), fd, 1, S_mus_file_clipping, "an integer");
  583. return(C_bool_to_Xen_boolean(mus_file_clipping(Xen_integer_to_C_int(fd))));
  584. }
  585. static Xen g_mus_file_set_clipping(Xen fd, Xen clipped)
  586. {
  587. Xen_check_type(Xen_is_integer(fd), fd, 1, S_set S_mus_file_clipping, "an integer");
  588. Xen_check_type(Xen_is_boolean(clipped), clipped, 2, S_set S_mus_file_clipping, "a boolean");
  589. return(C_bool_to_Xen_boolean(mus_file_set_clipping(Xen_integer_to_C_int(fd), Xen_boolean_to_C_bool(clipped))));
  590. }
  591. Xen g_mus_expand_filename(Xen file)
  592. {
  593. #define H_mus_expand_filename "(" S_mus_expand_filename " name): expand 'name' into a canonical or absolute filename, that is, \
  594. one in which all directories in the path are explicit."
  595. char *str = NULL;
  596. Xen result;
  597. Xen_check_type(Xen_is_string(file), file, 1, S_mus_expand_filename, "a string");
  598. str = mus_expand_filename(Xen_string_to_C_string(file));
  599. result = C_string_to_Xen_string(str);
  600. if (str) free(str);
  601. return(result);
  602. }
  603. static Xen g_mus_sound_report_cache(Xen file)
  604. {
  605. #define H_mus_sound_report_cache "(" S_mus_sound_report_cache " (name)): print the current sound \
  606. cache info to the file given or stdout"
  607. const char *name;
  608. if (!Xen_is_bound(file))
  609. {
  610. mus_sound_report_cache(stdout);
  611. return(Xen_false);
  612. }
  613. Xen_check_type(Xen_is_string(file), file, 1, S_mus_sound_report_cache, "a string");
  614. name = Xen_string_to_C_string(file);
  615. if (name)
  616. {
  617. char *str = NULL;
  618. str = mus_expand_filename(name);
  619. if (str)
  620. {
  621. FILE *fd;
  622. fd = FOPEN(str, "w");
  623. free(str);
  624. if (fd)
  625. {
  626. mus_sound_report_cache(fd);
  627. FCLOSE(fd, name);
  628. return(file);
  629. }
  630. }
  631. }
  632. Xen_error(Xen_make_error_type("cannot-save"),
  633. Xen_list_3(C_string_to_Xen_string(S_mus_sound_report_cache ": ~S ~A"),
  634. file,
  635. C_string_to_Xen_string(STRERROR(errno))));
  636. return(Xen_false);
  637. }
  638. static Xen g_mus_error_type_to_string(Xen err)
  639. {
  640. #define H_mus_error_type_to_string "(" S_mus_error_type_to_string " err): string description of err (a sndlib error type)"
  641. Xen_check_type(Xen_is_integer(err), err, 1, S_mus_error_type_to_string, "an integer");
  642. return(C_string_to_Xen_string((char *)mus_error_type_to_string(Xen_integer_to_C_int(err))));
  643. }
  644. static Xen g_array_to_file(Xen filename, Xen data, Xen len, Xen srate, Xen channels)
  645. {
  646. #define H_array_to_file "(" S_array_to_file " filename data len srate channels): write 'data', \
  647. a " S_vct " of interleaved samples, to the sound file 'filename' set up to have the given \
  648. srate and channels. 'len' samples are written."
  649. /* this exists for compatibility with the Common Lisp version of CLM. Ideally, we'd get rid
  650. * of it and provide vct<->file and sound-data<->file instead so that the channels aren't
  651. * handled through interleaving. But that means extensive changes to the Lisp code...
  652. */
  653. mus_long_t olen, samps;
  654. vct *v;
  655. Xen_check_type(Xen_is_string(filename), filename, 1, S_array_to_file, "a string");
  656. Xen_check_type(mus_is_vct(data), data, 2, S_array_to_file, "a " S_vct);
  657. Xen_check_type(Xen_is_llong(len), len, 3, S_array_to_file, "an integer");
  658. Xen_check_type(Xen_is_integer(srate), srate, 4, S_array_to_file, "an integer");
  659. Xen_check_type(Xen_is_integer(channels), channels, 5, S_array_to_file, "an integer");
  660. v = Xen_to_vct(data);
  661. samps = Xen_llong_to_C_llong(len);
  662. if (samps <= 0)
  663. Xen_out_of_range_error(S_array_to_file, 3, len, "samples <= 0?");
  664. if (samps > mus_vct_length(v))
  665. samps = mus_vct_length(v);
  666. olen = mus_float_array_to_file(Xen_string_to_C_string(filename),
  667. mus_vct_data(v),
  668. samps,
  669. Xen_integer_to_C_int(srate),
  670. Xen_integer_to_C_int(channels));
  671. return(C_llong_to_Xen_llong(olen));
  672. }
  673. static Xen g_file_to_array(Xen filename, Xen chan, Xen start, Xen samples, Xen data)
  674. {
  675. #define H_file_to_array "(" S_file_to_array " filename chan start samples data): read the sound file \
  676. 'filename' placing samples from channel 'chan' into the " S_vct " 'data' starting in the file \
  677. at frample 'start' and reading 'samples' samples altogether."
  678. int chn, chans;
  679. mus_long_t samps;
  680. vct *v;
  681. const char *name = NULL;
  682. Xen_check_type(Xen_is_string(filename), filename, 1, S_file_to_array, "a string");
  683. Xen_check_type(Xen_is_integer(chan), chan, 2, S_file_to_array, "an integer");
  684. Xen_check_type(Xen_is_llong(start), start, 3, S_file_to_array, "an integer");
  685. Xen_check_type(Xen_is_llong(samples), samples, 4, S_file_to_array, "an integer");
  686. Xen_check_type((mus_is_vct(data)), data, 5, S_file_to_array, "a " S_vct);
  687. name = Xen_string_to_C_string(filename);
  688. if (!(mus_file_probe(name)))
  689. Xen_error(NO_SUCH_FILE,
  690. Xen_list_3(C_string_to_Xen_string(S_file_to_array ": ~S ~A"),
  691. filename,
  692. C_string_to_Xen_string(STRERROR(errno))));
  693. v = Xen_to_vct(data);
  694. samps = Xen_llong_to_C_llong(samples);
  695. if (samps <= 0)
  696. Xen_out_of_range_error(S_file_to_array, 4, samples, "samples <= 0?");
  697. if (samps > mus_vct_length(v))
  698. samps = mus_vct_length(v);
  699. chn = Xen_integer_to_C_int(chan);
  700. chans = mus_sound_chans(name);
  701. if ((chn < 0) || (chn > chans))
  702. Xen_error(NO_SUCH_CHANNEL,
  703. Xen_list_4(C_string_to_Xen_string(S_file_to_array ": invalid chan: ~A, ~S has ~A chans"),
  704. chan,
  705. filename,
  706. C_int_to_Xen_integer(chans)));
  707. if (chans <= 0)
  708. Xen_error(BAD_HEADER,
  709. Xen_list_2(C_string_to_Xen_string(S_file_to_array ": ~S chans <= 0"),
  710. filename));
  711. mus_file_to_float_array(name, chn, Xen_llong_to_C_llong(start), samps, mus_vct_data(v));
  712. return(data);
  713. }
  714. static Xen new_sound_hook;
  715. static void g_new_sound_hook(const char *filename)
  716. {
  717. if (Xen_hook_has_list(new_sound_hook))
  718. {
  719. #if HAVE_SCHEME
  720. s7_call(s7, new_sound_hook, s7_cons(s7, C_string_to_Xen_string(filename), Xen_empty_list));
  721. #else
  722. Xen procs, fname;
  723. fname = C_string_to_Xen_string(filename);
  724. procs = Xen_hook_list(new_sound_hook);
  725. while (!Xen_is_null(procs))
  726. {
  727. Xen_call_with_1_arg(Xen_car(procs), fname, S_new_sound_hook);
  728. procs = Xen_cdr(procs);
  729. }
  730. #endif
  731. }
  732. }
  733. static Xen sound_path;
  734. Xen g_mus_sound_path(void)
  735. {
  736. #define H_mus_sound_path "(" S_mus_sound_path "): a list of directories to search for sound files."
  737. return(sound_path);
  738. }
  739. #if HAVE_SCHEME
  740. static int sound_path_loc = -1;
  741. static s7_pointer mus_sound_path_symbol;
  742. #endif
  743. static Xen g_mus_set_sound_path(Xen val)
  744. {
  745. Xen_check_type(Xen_is_list(val), val, 1, S_set S_mus_sound_path, "a list");
  746. #if HAVE_SCHEME
  747. if (sound_path_loc != -1)
  748. s7_gc_unprotect_at(s7, sound_path_loc);
  749. sound_path = val;
  750. sound_path_loc = s7_gc_protect(s7, sound_path);
  751. s7_symbol_set_value(s7, mus_sound_path_symbol, val);
  752. #else
  753. if (sound_path != Xen_empty_list)
  754. Xen_GC_unprotect(sound_path);
  755. Xen_GC_protect(val);
  756. sound_path = val;
  757. #endif
  758. return(val);
  759. }
  760. static Xen g_mus_max_malloc(void)
  761. {
  762. #define H_mus_max_malloc "(" S_mus_max_malloc "): maximum number of bytes we will try to malloc."
  763. return(C_llong_to_Xen_llong(mus_max_malloc()));
  764. }
  765. #if HAVE_SCHEME
  766. static s7_pointer mus_max_malloc_symbol;
  767. #endif
  768. static Xen g_mus_set_max_malloc(Xen val)
  769. {
  770. mus_long_t size;
  771. Xen_check_type(Xen_is_llong(val), val, 1, S_set S_mus_max_malloc, "an integer");
  772. size = Xen_llong_to_C_llong(val);
  773. #if HAVE_SCHEME
  774. s7_symbol_set_value(s7, mus_max_malloc_symbol, s7_make_integer(s7, size));
  775. #endif
  776. return(C_llong_to_Xen_llong(mus_set_max_malloc(size)));
  777. }
  778. static Xen g_mus_max_table_size(void)
  779. {
  780. #define H_mus_max_table_size "(" S_mus_max_table_size "): maximum table size."
  781. return(C_llong_to_Xen_llong(mus_max_table_size()));
  782. }
  783. #if HAVE_SCHEME
  784. static s7_pointer mus_max_table_size_symbol;
  785. #endif
  786. static Xen g_mus_set_max_table_size(Xen val)
  787. {
  788. mus_long_t size;
  789. Xen_check_type(Xen_is_llong(val), val, 1, S_set S_mus_max_table_size, "an integer");
  790. size = Xen_llong_to_C_llong(val);
  791. #if HAVE_SCHEME
  792. s7_symbol_set_value(s7, mus_max_table_size_symbol, s7_make_integer(s7, size));
  793. #endif
  794. return(C_llong_to_Xen_llong(mus_set_max_table_size(size)));
  795. }
  796. #if __APPLE__
  797. #define S_mus_audio_output_properties_mutable "mus-audio-output-properties-mutable"
  798. static Xen g_mus_audio_output_properties_mutable(Xen mut)
  799. {
  800. #define H_mus_audio_output_properties_mutable "(" S_mus_audio_output_properties_mutable " val): can DAC settings be changed to match the current sound"
  801. Xen_check_type(Xen_is_boolean(mut), mut, 1, S_mus_audio_output_properties_mutable, "a boolean");
  802. return(C_bool_to_Xen_boolean(mus_audio_output_properties_mutable(Xen_boolean_to_C_bool(mut))));
  803. }
  804. #endif
  805. Xen_wrap_1_arg(g_mus_sound_samples_w, g_mus_sound_samples)
  806. Xen_wrap_2_args(g_mus_sound_set_samples_w, g_mus_sound_set_samples)
  807. Xen_wrap_1_arg(g_mus_sound_framples_w, g_mus_sound_framples)
  808. Xen_wrap_1_arg(g_mus_sound_duration_w, g_mus_sound_duration)
  809. Xen_wrap_1_arg(g_mus_sound_datum_size_w, g_mus_sound_datum_size)
  810. Xen_wrap_1_arg(g_mus_sound_data_location_w, g_mus_sound_data_location)
  811. Xen_wrap_2_args(g_mus_sound_set_data_location_w, g_mus_sound_set_data_location)
  812. Xen_wrap_1_arg(g_mus_sound_chans_w, g_mus_sound_chans)
  813. Xen_wrap_2_args(g_mus_sound_set_chans_w, g_mus_sound_set_chans)
  814. Xen_wrap_1_arg(g_mus_sound_srate_w, g_mus_sound_srate)
  815. Xen_wrap_2_args(g_mus_sound_set_srate_w, g_mus_sound_set_srate)
  816. Xen_wrap_1_arg(g_mus_sound_header_type_w, g_mus_sound_header_type)
  817. Xen_wrap_2_args(g_mus_sound_set_header_type_w, g_mus_sound_set_header_type)
  818. Xen_wrap_1_arg(g_mus_sound_sample_type_w, g_mus_sound_sample_type)
  819. Xen_wrap_2_args(g_mus_sound_set_sample_type_w, g_mus_sound_set_sample_type)
  820. Xen_wrap_1_arg(g_mus_sound_length_w, g_mus_sound_length)
  821. Xen_wrap_1_arg(g_mus_sound_type_specifier_w, g_mus_sound_type_specifier)
  822. Xen_wrap_1_arg(g_mus_header_type_name_w, g_mus_header_type_name)
  823. Xen_wrap_1_arg(g_mus_header_type_to_string_w, g_mus_header_type_to_string)
  824. Xen_wrap_1_arg(g_mus_sample_type_name_w, g_mus_sample_type_name)
  825. Xen_wrap_1_arg(g_mus_sample_type_to_string_w, g_mus_sample_type_to_string)
  826. Xen_wrap_1_arg(g_mus_sound_comment_w, g_mus_sound_comment)
  827. Xen_wrap_1_arg(g_mus_sound_write_date_w, g_mus_sound_write_date)
  828. Xen_wrap_1_arg(g_mus_bytes_per_sample_w, g_mus_bytes_per_sample)
  829. Xen_wrap_1_arg(g_mus_sound_loop_info_w, g_mus_sound_loop_info)
  830. Xen_wrap_1_arg(g_mus_sound_mark_info_w, g_mus_sound_mark_info)
  831. Xen_wrap_1_arg(g_mus_sound_maxamp_w, g_mus_sound_maxamp)
  832. Xen_wrap_2_args(g_mus_sound_set_maxamp_w, g_mus_sound_set_maxamp)
  833. Xen_wrap_1_arg(g_mus_sound_maxamp_exists_w, g_mus_sound_maxamp_exists)
  834. Xen_wrap_1_arg(g_mus_sound_preload_w, g_mus_sound_preload)
  835. Xen_wrap_no_args(g_mus_clipping_w, g_mus_clipping)
  836. Xen_wrap_1_arg(g_mus_set_clipping_w, g_mus_set_clipping)
  837. Xen_wrap_1_arg(g_mus_file_clipping_w, g_mus_file_clipping)
  838. Xen_wrap_2_args(g_mus_file_set_clipping_w, g_mus_file_set_clipping)
  839. Xen_wrap_no_args(g_mus_header_raw_defaults_w, g_mus_header_raw_defaults)
  840. Xen_wrap_1_arg(g_mus_header_set_raw_defaults_w, g_mus_header_set_raw_defaults)
  841. Xen_wrap_2_args(g_mus_header_writable_w, g_mus_header_writable)
  842. Xen_wrap_1_arg(g_mus_expand_filename_w, g_mus_expand_filename)
  843. Xen_wrap_1_optional_arg(g_mus_sound_report_cache_w, g_mus_sound_report_cache)
  844. Xen_wrap_1_arg(g_mus_sound_forget_w, g_mus_sound_forget)
  845. Xen_wrap_no_args(g_mus_sound_prune_w, g_mus_sound_prune)
  846. Xen_wrap_1_arg(g_mus_error_type_to_string_w, g_mus_error_type_to_string)
  847. Xen_wrap_2_args(g_mus_oss_set_buffers_w, g_mus_oss_set_buffers)
  848. Xen_wrap_5_args(g_array_to_file_w, g_array_to_file)
  849. Xen_wrap_5_args(g_file_to_array_w, g_file_to_array)
  850. Xen_wrap_no_args(g_mus_alsa_buffers_w, g_mus_alsa_buffers)
  851. Xen_wrap_1_arg(g_mus_alsa_set_buffers_w, g_mus_alsa_set_buffers)
  852. Xen_wrap_no_args(g_mus_alsa_buffer_size_w, g_mus_alsa_buffer_size)
  853. Xen_wrap_1_arg(g_mus_alsa_set_buffer_size_w, g_mus_alsa_set_buffer_size)
  854. Xen_wrap_no_args(g_mus_alsa_device_w, g_mus_alsa_device)
  855. Xen_wrap_1_arg(g_mus_alsa_set_device_w, g_mus_alsa_set_device)
  856. Xen_wrap_no_args(g_mus_alsa_playback_device_w, g_mus_alsa_playback_device)
  857. Xen_wrap_1_arg(g_mus_alsa_set_playback_device_w, g_mus_alsa_set_playback_device)
  858. Xen_wrap_no_args(g_mus_alsa_capture_device_w, g_mus_alsa_capture_device)
  859. Xen_wrap_1_arg(g_mus_alsa_set_capture_device_w, g_mus_alsa_set_capture_device)
  860. Xen_wrap_no_args(g_mus_alsa_squelch_warning_w, g_mus_alsa_squelch_warning)
  861. Xen_wrap_1_arg(g_mus_alsa_set_squelch_warning_w, g_mus_alsa_set_squelch_warning)
  862. #if __APPLE__
  863. Xen_wrap_1_arg(g_mus_audio_output_properties_mutable_w, g_mus_audio_output_properties_mutable)
  864. #endif
  865. Xen_wrap_no_args(g_mus_max_malloc_w, g_mus_max_malloc)
  866. Xen_wrap_1_arg(g_mus_set_max_malloc_w, g_mus_set_max_malloc)
  867. Xen_wrap_no_args(g_mus_max_table_size_w, g_mus_max_table_size)
  868. Xen_wrap_1_arg(g_mus_set_max_table_size_w, g_mus_set_max_table_size)
  869. Xen_wrap_no_args(g_mus_sound_path_w, g_mus_sound_path)
  870. Xen_wrap_1_arg(g_mus_set_sound_path_w, g_mus_set_sound_path)
  871. #if HAVE_SCHEME
  872. static s7_pointer acc_mus_max_table_size(s7_scheme *sc, s7_pointer args) {return(g_mus_set_max_table_size(s7_cadr(args)));}
  873. static s7_pointer acc_mus_max_malloc(s7_scheme *sc, s7_pointer args) {return(g_mus_set_max_malloc(s7_cadr(args)));}
  874. static s7_pointer acc_mus_sound_path(s7_scheme *sc, s7_pointer args) {return(g_mus_set_sound_path(s7_cadr(args)));}
  875. #endif
  876. void mus_sndlib_xen_initialize(void)
  877. {
  878. #if HAVE_SCHEME
  879. s7_pointer pl_is, pl_isi, pl_si, pl_ss, pl_ps, pl_psp, pl_i, pl_bii, pl_p, pl_rs, pl_bi, pl_bib, pl_b, pl_ls;
  880. s7_pointer pl_l, pl_isfiii, pl_fsiiif, pl_bs, pl_ts, pl_sh, pl_bhi;
  881. #endif
  882. mus_sound_initialize();
  883. sound_path = Xen_empty_list;
  884. #if HAVE_RUBY
  885. Init_Hook();
  886. #endif
  887. Xen_define_constant(S_mus_out_format, MUS_OUT_SAMPLE_TYPE, "sample type for fastest IO");
  888. Xen_define_constant(S_mus_unknown_header, MUS_UNKNOWN_HEADER, "unknown header type");
  889. Xen_define_constant(S_mus_next, MUS_NEXT, "NeXT (Sun) sound header id");
  890. Xen_define_constant(S_mus_aifc, MUS_AIFC, "AIFC sound header id");
  891. Xen_define_constant(S_mus_rf64, MUS_RF64, "RF64 sound header id");
  892. Xen_define_constant(S_mus_riff, MUS_RIFF, "RIFF (MS wave) sound header id");
  893. Xen_define_constant(S_mus_nist, MUS_NIST, "NIST (Sphere) sound header id");
  894. Xen_define_constant(S_mus_raw, MUS_RAW, "raw (headerless) sound header id");
  895. Xen_define_constant(S_mus_ircam, MUS_IRCAM, "IRCAM sound header id");
  896. Xen_define_constant(S_mus_aiff, MUS_AIFF, "AIFF (old-style) sound header id");
  897. Xen_define_constant(S_mus_bicsf, MUS_BICSF, "BICSF header id");
  898. Xen_define_constant(S_mus_voc, MUS_VOC, "VOC header id");
  899. Xen_define_constant(S_mus_svx, MUS_SVX, "SVX (IFF) header id");
  900. Xen_define_constant(S_mus_soundfont, MUS_SOUNDFONT, "soundfont header id");
  901. Xen_define_constant(S_mus_caff, MUS_CAFF, "Apple Core Audio File Format header id");
  902. Xen_define_constant(S_mus_unknown_sample, MUS_UNKNOWN_SAMPLE, "unknown sample type");
  903. Xen_define_constant(S_mus_bshort, MUS_BSHORT, "big-endian short sample type id");
  904. Xen_define_constant(S_mus_lshort, MUS_LSHORT, "little-endian short sample type id");
  905. Xen_define_constant(S_mus_mulaw, MUS_MULAW, "mulaw (8-bit) sample type id");
  906. Xen_define_constant(S_mus_alaw, MUS_ALAW, "alaw (8-bit) sample type id");
  907. Xen_define_constant(S_mus_byte, MUS_BYTE, "signed byte sample type id");
  908. Xen_define_constant(S_mus_ubyte, MUS_UBYTE, "unsigned byte sample type id");
  909. Xen_define_constant(S_mus_bfloat, MUS_BFLOAT, "big-endian float sample type id");
  910. Xen_define_constant(S_mus_lfloat, MUS_LFLOAT, "little-endian float sample type id");
  911. Xen_define_constant(S_mus_bint, MUS_BINT, "big-endian int sample type id");
  912. Xen_define_constant(S_mus_lint, MUS_LINT, "little-endian int sample type id");
  913. Xen_define_constant(S_mus_bintn, MUS_BINTN, "normalized big-endian int sample type id");
  914. Xen_define_constant(S_mus_lintn, MUS_LINTN, "normalized little-endian int sample type id");
  915. Xen_define_constant(S_mus_b24int, MUS_B24INT, "big-endian 24-bit sample type id");
  916. Xen_define_constant(S_mus_l24int, MUS_L24INT, "little-endian 24-bit sample type id");
  917. Xen_define_constant(S_mus_bdouble, MUS_BDOUBLE, "big-endian double sample type id");
  918. Xen_define_constant(S_mus_ldouble, MUS_LDOUBLE, "little-endian double sample type id");
  919. Xen_define_constant(S_mus_ubshort, MUS_UBSHORT, "unsigned big-endian short sample type id");
  920. Xen_define_constant(S_mus_ulshort, MUS_ULSHORT, "unsigned little-endian short sample type id");
  921. Xen_define_constant(S_mus_bdouble_unscaled, MUS_BDOUBLE_UNSCALED, "unscaled big-endian double sample type id");
  922. Xen_define_constant(S_mus_ldouble_unscaled, MUS_LDOUBLE_UNSCALED, "unscaled little-endian double sample type id");
  923. Xen_define_constant(S_mus_bfloat_unscaled, MUS_BFLOAT_UNSCALED, "unscaled big-endian float sample type id");
  924. Xen_define_constant(S_mus_lfloat_unscaled, MUS_LFLOAT_UNSCALED, "unscaled little-endian float sample type id");
  925. #if HAVE_SCHEME
  926. s7_eval_c_string(s7,
  927. "(define (mus_header_t? form argn) \
  928. (let ((h (list-ref form argn))) \
  929. (if (not (memq h '(mus-next mus-aifc mus-riff mus-nist mus-raw mus-ircam mus-aiff mus-bicsf mus-voc mus-svx mus-soundfont mus-rf64 mus-caff))) \
  930. (if (not (integer? h)) \
  931. 'integer? \
  932. (if (not (< 0 h 71)) \
  933. \"an integer between 1 and 70\")))))");
  934. {
  935. s7_pointer s, i, p, b, r, f, t, l, h;
  936. s = s7_make_symbol(s7, "string?");
  937. i = s7_make_symbol(s7, "integer?");
  938. p = s7_make_symbol(s7, "pair?");
  939. l = s7_make_symbol(s7, "list?");
  940. b = s7_make_symbol(s7, "boolean?");
  941. r = s7_make_symbol(s7, "real?");
  942. f = s7_make_symbol(s7, "float-vector?");
  943. h = s7_make_symbol(s7, "mus_header_t?");
  944. t = s7_t(s7);
  945. pl_is = s7_make_signature(s7, 2, i, s);
  946. pl_isi = s7_make_signature(s7, 3, i, s, i);
  947. pl_si = s7_make_signature(s7, 2, s, i);
  948. pl_sh = s7_make_signature(s7, 2, s, h);
  949. pl_ss = s7_make_signature(s7, 2, s, s);
  950. pl_ts = s7_make_signature(s7, 2, t, s);
  951. pl_ls = s7_make_signature(s7, 2, l, s);
  952. pl_ps = s7_make_signature(s7, 2, p, s);
  953. pl_psp = s7_make_signature(s7, 3, p, s, p);
  954. pl_i = s7_make_circular_signature(s7, 0, 1, i);
  955. pl_bii = s7_make_signature(s7, 3, b, i, i);
  956. pl_bhi = s7_make_signature(s7, 3, b, h, i);
  957. pl_p = s7_make_circular_signature(s7, 0, 1, p);
  958. pl_l = s7_make_circular_signature(s7, 0, 1, l);
  959. pl_rs = s7_make_signature(s7, 2, r, s);
  960. pl_bi = s7_make_signature(s7, 2, b, i);
  961. pl_bib = s7_make_signature(s7, 3, b, i, b);
  962. pl_b = s7_make_circular_signature(s7, 0, 1, b);
  963. pl_bs = s7_make_signature(s7, 2, b, s);
  964. pl_isfiii = s7_make_signature(s7, 6, i, s, f, i, i, i);
  965. pl_fsiiif = s7_make_signature(s7, 6, f, s, i, i, i, f);
  966. }
  967. #endif
  968. Xen_define_typed_dilambda(S_mus_sound_samples, g_mus_sound_samples_w, H_mus_sound_samples,
  969. S_set S_mus_sound_samples, g_mus_sound_set_samples_w, 1, 0, 2, 0, pl_is, pl_isi);
  970. Xen_define_typed_dilambda(S_mus_sound_data_location, g_mus_sound_data_location_w, H_mus_sound_data_location,
  971. S_set S_mus_sound_data_location, g_mus_sound_set_data_location_w, 1, 0, 2, 0, pl_is, pl_isi);
  972. Xen_define_typed_dilambda(S_mus_sound_chans, g_mus_sound_chans_w, H_mus_sound_chans,
  973. S_set S_mus_sound_chans, g_mus_sound_set_chans_w, 1, 0, 2, 0, pl_is, pl_isi);
  974. Xen_define_typed_dilambda(S_mus_sound_srate, g_mus_sound_srate_w, H_mus_sound_srate,
  975. S_set S_mus_sound_srate, g_mus_sound_set_srate_w, 1, 0, 2, 0, pl_is, pl_isi);
  976. Xen_define_typed_dilambda(S_mus_sound_header_type, g_mus_sound_header_type_w, H_mus_sound_header_type,
  977. S_set S_mus_sound_header_type, g_mus_sound_set_header_type_w, 1, 0, 2, 0, pl_is, pl_isi);
  978. Xen_define_typed_dilambda(S_mus_sound_sample_type, g_mus_sound_sample_type_w, H_mus_sound_sample_type,
  979. S_set S_mus_sound_sample_type, g_mus_sound_set_sample_type_w, 1, 0, 2, 0, pl_is, pl_isi);
  980. Xen_define_typed_procedure(S_mus_sound_framples, g_mus_sound_framples_w, 1, 0, 0, H_mus_sound_framples, pl_is);
  981. Xen_define_typed_procedure("mus-sound-frames", g_mus_sound_framples_w, 1, 0, 0, H_mus_sound_framples, pl_is);
  982. Xen_define_typed_procedure(S_mus_sound_duration, g_mus_sound_duration_w, 1, 0, 0, H_mus_sound_duration, pl_rs);
  983. Xen_define_typed_procedure(S_mus_sound_datum_size, g_mus_sound_datum_size_w, 1, 0, 0, H_mus_sound_datum_size, pl_is);
  984. Xen_define_typed_procedure(S_mus_sound_length, g_mus_sound_length_w, 1, 0, 0, H_mus_sound_length, pl_is);
  985. Xen_define_typed_procedure(S_mus_sound_type_specifier, g_mus_sound_type_specifier_w, 1, 0, 0, H_mus_sound_type_specifier, pl_is);
  986. Xen_define_typed_procedure(S_mus_header_type_name, g_mus_header_type_name_w, 1, 0, 0, H_mus_header_type_name, pl_sh);
  987. Xen_define_typed_procedure(S_mus_header_type_to_string,g_mus_header_type_to_string_w, 1, 0, 0, H_mus_header_type_to_string, pl_sh);
  988. Xen_define_typed_procedure(S_mus_header_writable, g_mus_header_writable_w, 2, 0, 0, H_mus_header_writable, pl_bhi);
  989. Xen_define_typed_procedure(S_mus_sample_type_name, g_mus_sample_type_name_w, 1, 0, 0, H_mus_sample_type_name, pl_si);
  990. Xen_define_typed_procedure(S_mus_sample_type_to_string,g_mus_sample_type_to_string_w, 1, 0, 0, H_mus_sample_type_to_string, pl_si);
  991. Xen_define_typed_procedure(S_mus_sound_comment, g_mus_sound_comment_w, 1, 0, 0, H_mus_sound_comment, pl_ts);
  992. Xen_define_typed_procedure(S_mus_sound_write_date, g_mus_sound_write_date_w, 1, 0, 0, H_mus_sound_write_date, pl_is);
  993. Xen_define_typed_procedure(S_mus_bytes_per_sample, g_mus_bytes_per_sample_w, 1, 0, 0, H_mus_bytes_per_sample, pl_i);
  994. Xen_define_typed_procedure(S_mus_sound_loop_info, g_mus_sound_loop_info_w, 1, 0, 0, H_mus_sound_loop_info, pl_ls);
  995. Xen_define_typed_procedure(S_mus_sound_mark_info, g_mus_sound_mark_info_w, 1, 0, 0, H_mus_sound_mark_info, pl_ps);
  996. Xen_define_typed_procedure(S_mus_sound_maxamp_exists, g_mus_sound_maxamp_exists_w, 1, 0, 0, H_mus_sound_maxamp_exists, pl_bs);
  997. Xen_define_typed_procedure(S_mus_sound_forget, g_mus_sound_forget_w, 1, 0, 0, H_mus_sound_forget, pl_is);
  998. Xen_define_typed_procedure(S_mus_sound_prune, g_mus_sound_prune_w, 0, 0, 0, H_mus_sound_prune, pl_i);
  999. Xen_define_typed_procedure(S_mus_expand_filename, g_mus_expand_filename_w, 1, 0, 0, H_mus_expand_filename, pl_ss);
  1000. Xen_define_typed_procedure(S_mus_sound_report_cache, g_mus_sound_report_cache_w, 0, 1, 0, H_mus_sound_report_cache, NULL);
  1001. Xen_define_typed_procedure(S_mus_error_type_to_string, g_mus_error_type_to_string_w, 1, 0, 0, H_mus_error_type_to_string, pl_si);
  1002. Xen_define_typed_procedure(S_mus_oss_set_buffers, g_mus_oss_set_buffers_w, 2, 0, 0, H_mus_oss_set_buffers, pl_bii);
  1003. Xen_define_typed_procedure(S_array_to_file, g_array_to_file_w, 5, 0, 0, H_array_to_file, pl_isfiii);
  1004. Xen_define_typed_procedure(S_file_to_array, g_file_to_array_w, 5, 0, 0, H_file_to_array, pl_fsiiif);
  1005. Xen_define_typed_procedure(S_mus_sound_preload, g_mus_sound_preload_w, 1, 0, 0, H_mus_sound_preload, pl_ss);
  1006. Xen_define_typed_dilambda(S_mus_header_raw_defaults, g_mus_header_raw_defaults_w, H_mus_header_raw_defaults,
  1007. S_set S_mus_header_raw_defaults, g_mus_header_set_raw_defaults_w, 0, 0, 1, 0, pl_p, pl_p);
  1008. Xen_define_typed_dilambda(S_mus_clipping, g_mus_clipping_w, H_mus_clipping,
  1009. S_set S_mus_clipping, g_mus_set_clipping_w, 0, 0, 1, 0, pl_b, pl_b);
  1010. Xen_define_typed_dilambda(S_mus_file_clipping, g_mus_file_clipping_w, H_mus_file_clipping,
  1011. S_set S_mus_file_clipping, g_mus_file_set_clipping_w, 1, 0, 2, 0, pl_bi, pl_bib);
  1012. Xen_define_typed_dilambda(S_mus_sound_maxamp, g_mus_sound_maxamp_w, H_mus_sound_maxamp,
  1013. S_set S_mus_sound_maxamp, g_mus_sound_set_maxamp_w, 1, 0, 2, 0, pl_ps, pl_psp);
  1014. /* these are no-ops if not ALSA, but that makes it easier to maintain global initialization files */
  1015. Xen_define_typed_dilambda(S_mus_alsa_buffers, g_mus_alsa_buffers_w, H_mus_alsa_buffers, S_set
  1016. S_mus_alsa_buffers, g_mus_alsa_set_buffers_w, 0, 0, 1, 0, NULL, NULL);
  1017. Xen_define_typed_dilambda(S_mus_alsa_buffer_size, g_mus_alsa_buffer_size_w, H_mus_alsa_buffer_size,
  1018. S_set S_mus_alsa_buffer_size, g_mus_alsa_set_buffer_size_w, 0, 0, 1, 0, NULL, NULL);
  1019. Xen_define_typed_dilambda(S_mus_alsa_device, g_mus_alsa_device_w, H_mus_alsa_device,
  1020. S_set S_mus_alsa_device, g_mus_alsa_set_device_w, 0, 0, 1, 0, NULL, NULL);
  1021. Xen_define_typed_dilambda(S_mus_alsa_playback_device, g_mus_alsa_playback_device_w, H_mus_alsa_playback_device,
  1022. S_set S_mus_alsa_playback_device, g_mus_alsa_set_playback_device_w, 0, 0, 1, 0, NULL, NULL);
  1023. Xen_define_typed_dilambda(S_mus_alsa_capture_device, g_mus_alsa_capture_device_w, H_mus_alsa_capture_device,
  1024. S_set S_mus_alsa_capture_device, g_mus_alsa_set_capture_device_w, 0, 0, 1, 0, NULL, NULL);
  1025. Xen_define_typed_dilambda(S_mus_alsa_squelch_warning, g_mus_alsa_squelch_warning_w, H_mus_alsa_squelch_warning,
  1026. S_set S_mus_alsa_squelch_warning, g_mus_alsa_set_squelch_warning_w, 0, 0, 1, 0, NULL, NULL);
  1027. Xen_define_typed_dilambda(S_mus_max_malloc, g_mus_max_malloc_w, H_mus_max_malloc,
  1028. S_set S_mus_max_malloc, g_mus_set_max_malloc_w, 0, 0, 1, 0, pl_i, pl_i);
  1029. Xen_define_typed_dilambda(S_mus_max_table_size, g_mus_max_table_size_w, H_mus_max_table_size,
  1030. S_set S_mus_max_table_size, g_mus_set_max_table_size_w, 0, 0, 1, 0, pl_i, pl_i);
  1031. Xen_define_typed_dilambda(S_mus_sound_path, g_mus_sound_path_w, H_mus_sound_path,
  1032. S_set S_mus_sound_path, g_mus_set_sound_path_w, 0, 0, 1, 0, pl_l, pl_l);
  1033. #if HAVE_SCHEME
  1034. mus_max_table_size_symbol = s7_define_variable(s7, "*" S_mus_max_table_size "*", s7_make_integer(s7, MUS_MAX_TABLE_SIZE_DEFAULT));
  1035. s7_symbol_set_documentation(s7, mus_max_table_size_symbol, "*mus-max-table-size*: maximum table size.");
  1036. s7_symbol_set_access(s7, mus_max_table_size_symbol, s7_make_function(s7, "[acc-mus-max-table-size]" "]", acc_mus_max_table_size, 2, 0, false, "accessor"));
  1037. mus_max_malloc_symbol = s7_define_variable(s7, "*" S_mus_max_malloc "*", s7_make_integer(s7, MUS_MAX_MALLOC_DEFAULT));
  1038. s7_symbol_set_documentation(s7, mus_max_malloc_symbol, "*mus-max-malloc*: maximum number of bytes we will try to malloc.");
  1039. s7_symbol_set_access(s7, mus_max_malloc_symbol, s7_make_function(s7, "[acc-mus-max-malloc]" "]", acc_mus_max_malloc, 2, 0, false, "accessor"));
  1040. mus_sound_path_symbol = s7_define_variable(s7, "*" S_mus_sound_path "*", s7_nil(s7));
  1041. s7_symbol_set_documentation(s7, mus_sound_path_symbol, "*" S_mus_sound_path "* is a list of directories to search for sound files");
  1042. s7_symbol_set_access(s7, mus_sound_path_symbol, s7_make_function(s7, "[acc-mus-sound-path]" "]", acc_mus_sound_path, 2, 0, false, "accessor"));
  1043. #endif
  1044. #if __APPLE__
  1045. Xen_define_typed_procedure(S_mus_audio_output_properties_mutable, g_mus_audio_output_properties_mutable_w, 1, 0, 0, H_mus_audio_output_properties_mutable, pl_b);
  1046. #endif
  1047. #define H_new_sound_hook S_new_sound_hook "(name): called when a new sound file is being created"
  1048. new_sound_hook = Xen_define_hook(S_new_sound_hook, "(make-hook 'name)", 1, H_new_sound_hook);
  1049. mus_header_write_set_hook(g_new_sound_hook);
  1050. Xen_provide_feature("sndlib");
  1051. }