1 #include "snd.h"
2 #include "clm2xen.h"
3
4 /*
5 * each channel currently being played has an associated dac_info struct
6 * all active dac_info structs are held in a play_list
7 * channels can come and go as a play is in progress
8 */
9
10 /* -------------------------------- per-channel control-panel state -------------------------------- */
11
12 typedef struct {
13 mus_any *gen;
14 struct dac_info *dp;
15 bool speeding;
16 mus_float_t sr;
17 } spd_info;
18
19 typedef enum {DAC_NOTHING, DAC_CHANNEL, DAC_REGION, DAC_MIX, DAC_XEN} dac_source_t;
20
21 typedef struct dac_info {
22 dac_source_t type;
23 mus_float_t cur_index;
24 mus_float_t cur_amp;
25 mus_float_t cur_srate;
26 mus_float_t cur_exp;
27 mus_float_t cur_rev; /* rev scaler -- len is set at initialization */
28 mus_float_t contrast_amp;
29 bool expanding, reverbing, filtering; /* these need lots of preparation, so they're noticed only at the start */
30 int audio_chan; /* where channel's output is going (wrap-around if not enough audio output channels) */
31 int slot;
32 mus_float_t *a; /* filter coeffs */
33 int a_size; /* user can change filter order while playing (sigh...) */
34 snd_fd *chn_fd; /* sampler, null if DAC_Xen */
35 spd_info *spd;
36 mus_any *flt;
37 int region, mix_id; /* to reset region-browser play button upon completion */
38 bool selection;
39 mus_any *src;
40 snd_info *sp; /* needed to see button callback changes etc */
41 chan_info *cp;
42 bool never_sped;
43 int expand_ring_framples;
44 mus_long_t end;
45 Xen stop_procedure;
46 int stop_procedure_gc_loc;
47 Xen func;
48 int func_gc_loc, direction;
49 mus_float_t (*dac_sample)(struct dac_info *dp);
50 } dac_info;
51
52 #define AMP_CONTROL(sp, dp) ((dp->cp->amp_control) ? (dp->cp->amp_control[0]) : sp->amp_control)
53 /* an experiment */
54
55
dac_read_sample(struct dac_info * dp)56 static mus_float_t dac_read_sample(struct dac_info *dp)
57 {
58 return(read_sample(dp->chn_fd));
59 }
60
61
dac_no_sample(struct dac_info * dp)62 static mus_float_t dac_no_sample(struct dac_info *dp)
63 {
64 return(0.0);
65 }
66
67
dac_xen_sample(struct dac_info * dp)68 static mus_float_t dac_xen_sample(struct dac_info *dp)
69 {
70 Xen result;
71 result = Xen_unprotected_call_with_no_args(dp->func);
72 if (Xen_is_false(result))
73 {
74 dp->end = 0;
75 return(0.0);
76 }
77 return(Xen_real_to_C_double(result));
78 }
79
80
81 /* -------- filter -------- */
82
make_flt(dac_info * dp,int order,mus_float_t * env)83 static mus_any *make_flt(dac_info *dp, int order, mus_float_t *env)
84 {
85 if (order <= 0) return(NULL);
86 dp->a_size = order;
87 dp->a = (mus_float_t *)calloc(order, sizeof(mus_float_t));
88 if (env) mus_make_fir_coeffs(order, env, dp->a);
89 return(mus_make_fir_filter(order, dp->a, NULL));
90 }
91
92
93 /* -------- sample-rate conversion -------- */
94
dac_src_input_as_needed(void * arg,int direction)95 static mus_float_t dac_src_input_as_needed(void *arg, int direction)
96 {
97 dac_info *dp = (dac_info *)arg;
98 if ((direction != dp->direction) &&
99 (dp->chn_fd))
100 {
101 read_sample_change_direction(dp->chn_fd, (direction == 1) ? READ_FORWARD : READ_BACKWARD);
102 dp->direction = direction;
103 }
104 return((*(dp->dac_sample))(dp));
105 }
106
107
speed(dac_info * dp,mus_float_t sr)108 static mus_float_t speed(dac_info *dp, mus_float_t sr)
109 {
110 if (dp->never_sped)
111 return((*(dp->dac_sample))(dp));
112 if (!dp->src)
113 dp->src = mus_make_src(&dac_src_input_as_needed, sr, sinc_width(ss), (void *)dp);
114 mus_set_increment(dp->src, sr);
115 return(mus_src(dp->src, 0.0, &dac_src_input_as_needed));
116 }
117
118
119 /* -------- granular synthesis -------- */
120
expand_input_as_needed(void * arg,int dir)121 static mus_float_t expand_input_as_needed(void *arg, int dir)
122 {
123 spd_info *spd = (spd_info *)arg;
124 dac_info *dp;
125 dp = spd->dp;
126 if (spd->speeding)
127 return(speed(dp, spd->sr));
128 else return((*(dp->dac_sample))(dp));
129 }
130
131
max_expand_control_len(snd_info * sp)132 static int max_expand_control_len(snd_info *sp)
133 {
134 if (sp->expand_control_length > .5)
135 return(0);
136 return((int)(snd_srate(sp) * .5));
137 }
138
139
make_expand(snd_info * sp,mus_float_t initial_ex,dac_info * dp)140 static void *make_expand(snd_info *sp, mus_float_t initial_ex, dac_info *dp)
141 {
142 spd_info *spd;
143 spd = (spd_info *)calloc(1, sizeof(spd_info));
144 spd->gen = mus_make_granulate(&expand_input_as_needed,
145 initial_ex, sp->expand_control_length,
146 .6, /* expand scaler, not currently settable -- dac_set_expand_scaler below */
147 sp->expand_control_hop, sp->expand_control_ramp,
148 sp->expand_control_jitter,
149 max_expand_control_len(sp), NULL, (void *)spd);
150 spd->dp = dp;
151 spd->speeding = false;
152 spd->sr = 0.0;
153 return(spd);
154 }
155
156
free_expand(void * ur_spd)157 static void free_expand(void *ur_spd)
158 {
159 spd_info *spd = (spd_info *)ur_spd;
160 if (ur_spd)
161 {
162 mus_free(spd->gen);
163 free(spd);
164 }
165 }
166
167
expand(dac_info * dp,mus_float_t sr,mus_float_t ex)168 static mus_float_t expand(dac_info *dp, mus_float_t sr, mus_float_t ex)
169 {
170 /* from mixer.sai, used in "Leviathan", 1986 */
171 bool speeding;
172 snd_info *sp;
173 spd_info *spd;
174 sp = dp->sp;
175 speeding = ((sp->speed_control_direction != 1) || (!(snd_feq(sp->speed_control, 1.0))) || (!(snd_feq(dp->cur_srate, 1.0))));
176 spd = dp->spd;
177 spd->speeding = speeding;
178 spd->sr = sr;
179 return(mus_granulate(spd->gen, &expand_input_as_needed));
180 }
181
182
183 /* -------- reverb -------- */
184
185 /* to implement run-time reverb-length, we would need to save the individual delay lens, both nominal
186 and actual (given srate); set up the combs/allpasses to make room for 5.0 as reverb_control_length,
187 then at each call, check current reverb len (how?), and if not original, recalculate how many
188 samples each delay needs to be expanded by and so on -- more complexity than it's worth!
189 */
190
prime(int num)191 static int prime(int num)
192 {
193 if (num == 2) return(1);
194 if ((num % 2) == 1)
195 {
196 int lim, i;
197 lim = (int)(sqrt(num));
198 for (i = 3; i < lim; i += 2)
199 if ((num % i) == 0)
200 return(0);
201 return(1);
202 }
203 return(0);
204 }
205
206
get_prime(int num)207 static int get_prime(int num)
208 {
209 int i;
210 if ((num % 2) == 1)
211 i = num;
212 else i = num + 1;
213 while (!(prime(i))) i += 2;
214 return(i);
215 }
216
217
218 typedef struct {
219 int num_combs;
220 mus_any **combs;
221 int num_allpasses;
222 mus_any **allpasses;
223 mus_any *onep;
224 } rev_info;
225
226 static rev_info *global_rev = NULL;
227
nrev(rev_info * r,mus_float_t * rins,mus_float_t * routs,int chans)228 static void nrev(rev_info *r, mus_float_t *rins, mus_float_t *routs, int chans)
229 {
230 mus_float_t rout, rin = 0.0;
231 int i;
232 for (i = 0; i < chans; i++) rin += rins[i];
233 rout = mus_all_pass_unmodulated_noz(r->allpasses[3],
234 mus_one_pole(r->onep,
235 mus_all_pass_unmodulated_noz(r->allpasses[2],
236 mus_all_pass_unmodulated_noz(r->allpasses[1],
237 mus_all_pass_unmodulated_noz(r->allpasses[0],
238 mus_comb_unmodulated_noz(r->combs[0], rin) +
239 mus_comb_unmodulated_noz(r->combs[1], rin) +
240 mus_comb_unmodulated_noz(r->combs[2], rin) +
241 mus_comb_unmodulated_noz(r->combs[3], rin) +
242 mus_comb_unmodulated_noz(r->combs[4], rin) +
243 mus_comb_unmodulated_noz(r->combs[5], rin))))));
244 for (i = 0; i < chans; i++)
245 routs[i] = mus_all_pass_unmodulated_noz(r->allpasses[i + 4], rout);
246 }
247
248
249 static mus_float_t *r_ins, *r_outs;
250 static int reverb_chans = 0;
251
reverb(rev_info * r,mus_float_t ** rins,mus_float_t ** outs,int ind)252 static void reverb(rev_info *r, mus_float_t **rins, mus_float_t **outs, int ind)
253 {
254 int i, chans;
255 chans = reverb_chans;
256 for (i = 0; i < chans; i++)
257 {
258 r_ins[i] = rins[i][ind];
259 r_outs[i] = 0.0;
260 }
261 nrev(r, r_ins, r_outs, chans);
262 for (i = 0; i < chans; i++)
263 outs[i][ind] += (r_outs[i]);
264 }
265
266
free_reverb(void)267 static void free_reverb(void)
268 {
269 rev_info *r;
270 r = global_rev;
271 if (r)
272 {
273 int i;
274 if (r->combs)
275 {
276 for (i = 0; i < r->num_combs; i++)
277 if (r->combs[i])
278 mus_free(r->combs[i]);
279 free(r->combs);
280 }
281 if (r->onep) mus_free(r->onep);
282 if (r->allpasses)
283 {
284 for (i = 0; i < r->num_allpasses; i++)
285 if (r->allpasses[i])
286 mus_free(r->allpasses[i]);
287 free(r->allpasses);
288 }
289 free(r);
290 }
291 global_rev = NULL;
292 }
293
294
295 static mus_float_t *comb_factors = NULL;
296
make_nrev(snd_info * sp,int chans)297 static rev_info *make_nrev(snd_info *sp, int chans)
298 {
299 /* Mike McNabb's nrev from Mus10 days (ca. 1978) */
300 #define BASE_DLY_LEN 14
301 static int base_dly_len[BASE_DLY_LEN] = {1433, 1601, 1867, 2053, 2251, 2399, 347, 113, 37, 59, 43, 37, 29, 19};
302 static int dly_len[BASE_DLY_LEN];
303 #define NREV_COMBS 6
304 static mus_float_t nrev_comb_factors[NREV_COMBS] = {0.822, 0.802, 0.773, 0.753, 0.753, 0.733};
305 mus_float_t srscale;
306 int i, j, len;
307 rev_info *r;
308
309 if (!sp) return(NULL);
310
311 srscale = sp->reverb_control_length * snd_srate(sp) / 25641.0;
312 for (i = 0; i < BASE_DLY_LEN; i++)
313 dly_len[i] = get_prime((int)(srscale * base_dly_len[i]));
314 r = (rev_info *)calloc(1, sizeof(rev_info));
315 r->num_combs = NREV_COMBS;
316 r->combs = (mus_any **)calloc(r->num_combs, sizeof(mus_any *));
317 r->num_allpasses = 4 + chans;
318 r->allpasses = (mus_any **)calloc(r->num_allpasses, sizeof(mus_any *));
319
320 if (comb_factors) free(comb_factors);
321 comb_factors = (mus_float_t *)calloc(r->num_combs, sizeof(mus_float_t));
322 for (i = 0; i < r->num_combs; i++)
323 {
324 comb_factors[i] = nrev_comb_factors[i];
325 r->combs[i] = mus_make_comb(comb_factors[i] * sp->reverb_control_feedback, dly_len[i], NULL, dly_len[i], MUS_INTERP_LINEAR);
326 }
327
328 r->onep = mus_make_one_pole(sp->reverb_control_lowpass, sp->reverb_control_lowpass - 1.0);
329
330 for (i = 0, j = r->num_combs; i < 4; i++, j++)
331 r->allpasses[i] = mus_make_all_pass(-0.700, 0.700, dly_len[j], NULL, dly_len[j], MUS_INTERP_LINEAR);
332
333 for (i = 0, j = 10; i < chans; i++)
334 {
335 if (j < BASE_DLY_LEN)
336 len = dly_len[j];
337 else len = get_prime((int)(40 + mus_random(20.0)));
338 r->allpasses[i + 4] = mus_make_all_pass(-0.700, 0.700, len, NULL, len, MUS_INTERP_LINEAR);
339 }
340
341 return(r);
342 }
343
344
make_reverb(snd_info * sp,int chans)345 static void make_reverb(snd_info *sp, int chans)
346 {
347 reverb_chans = chans;
348 global_rev = make_nrev(sp, chans);
349 }
350
351
set_reverb_filter_coeff(mus_float_t newval)352 static void set_reverb_filter_coeff(mus_float_t newval)
353 {
354 if (global_rev)
355 {
356 mus_set_xcoeff(global_rev->onep, 0, newval);
357 mus_set_ycoeff(global_rev->onep, 1, 1.0 - newval);
358 }
359 }
360
361
set_reverb_comb_factors(mus_float_t val)362 static void set_reverb_comb_factors(mus_float_t val)
363 {
364 int j;
365 if (global_rev)
366 for (j = 0; j < global_rev->num_combs; j++)
367 mus_set_scaler(global_rev->combs[j], comb_factors[j] * val);
368 }
369
370
371 /* -------- contrast-enhancement -------- */
372
contrast(dac_info * dp,mus_float_t amp,mus_float_t index,mus_float_t inval)373 static mus_float_t contrast (dac_info *dp, mus_float_t amp, mus_float_t index, mus_float_t inval)
374 {
375 return(amp * mus_contrast_enhancement(dp->contrast_amp * inval, index));
376 }
377
378
379
380 static mus_error_handler_t *old_error_handler;
381 static bool got_local_error = false;
382
local_mus_error(int type,char * msg)383 static void local_mus_error(int type, char *msg)
384 {
385 got_local_error = true;
386 snd_error_without_format(msg);
387 }
388
389
sample_linear_env(env * e,int order)390 mus_float_t *sample_linear_env(env *e, int order)
391 {
392 /* used only for filter coeffs (env here is the frequency response curve) */
393 mus_any *ge;
394 int ordp;
395 mus_float_t *data = NULL;
396 mus_float_t last_x, step;
397
398 last_x = e->data[(e->pts - 1) * 2];
399 step = 2 * last_x / ((mus_float_t)order - 1);
400 ordp = e->pts;
401 if (ordp < order) ordp = order;
402
403 got_local_error = false;
404 old_error_handler = mus_error_set_handler(local_mus_error);
405 ge = mus_make_env(e->data, e->pts, 1.0, 0.0, e->base, 0.0, 1000 * ordp, NULL);
406 mus_error_set_handler(old_error_handler);
407
408 if (!got_local_error)
409 {
410 int i, j;
411 mus_float_t x;
412 data = (mus_float_t *)malloc(order * sizeof(mus_float_t));
413 for (i = 0, x = 0.0; i < order / 2; i++, x += step)
414 data[i] = mus_env_interp(x, ge);
415 for (j = order / 2 - 1, i = order / 2; (i < order) && (j >= 0); i++, j--)
416 data[i] = data[j];
417 mus_free(ge);
418 }
419
420 return(data);
421 }
422
423
free_dac_info(dac_info * dp,play_stop_t reason)424 static void free_dac_info(dac_info *dp, play_stop_t reason)
425 {
426 bool looping;
427 looping = (dp->stop_procedure == Xen_true);
428 if (dp->stop_procedure_gc_loc != NOT_A_GC_LOC)
429 {
430 Xen_call_with_1_arg(dp->stop_procedure,
431 C_int_to_Xen_integer((int)reason),
432 "play stop procedure");
433 snd_unprotect_at(dp->stop_procedure_gc_loc);
434 dp->stop_procedure = Xen_false;
435 dp->stop_procedure_gc_loc = NOT_A_GC_LOC;
436 }
437 if (dp->func_gc_loc != NOT_A_GC_LOC)
438 {
439 snd_unprotect_at(dp->func_gc_loc);
440 dp->func = Xen_false;
441 dp->func_gc_loc = NOT_A_GC_LOC;
442 }
443 if (dp->a) {free(dp->a); dp->a = NULL; dp->a_size = 0;}
444 dp->chn_fd = free_snd_fd(dp->chn_fd);
445 if (dp->spd) free_expand(dp->spd);
446 if (dp->src) mus_free(dp->src);
447 if (dp->flt) mus_free(dp->flt);
448 dp->sp = NULL;
449 dp->cp = NULL;
450 dp->type = DAC_NOTHING;
451 free(dp);
452 if ((looping) &&
453 (reason == PLAY_COMPLETE))
454 loop_play_selection();
455 }
456
457
458 static int dac_max_sounds = 0;
459 static dac_info **play_list = NULL;
460 #define INITIAL_MAX_SOUNDS 16
461 static int play_list_members = 0;
462 static int max_active_slot = -1;
463
464
465 /* -------------------------------- special control panel variables -------------------------------- */
466
467 typedef enum {DAC_EXPAND, DAC_EXPAND_RAMP, DAC_EXPAND_LENGTH, DAC_EXPAND_HOP, DAC_EXPAND_SCALER,
468 DAC_CONTRAST_AMP, DAC_REVERB_FEEDBACK, DAC_REVERB_LOWPASS} dac_field_t;
469
dac_set_field(snd_info * sp,mus_float_t newval,dac_field_t field)470 static void dac_set_field(snd_info *sp, mus_float_t newval, dac_field_t field)
471 {
472 /* if sp == NULL, sets globally */
473 if (play_list)
474 {
475 if (field == DAC_REVERB_LOWPASS)
476 {
477 if (global_rev)
478 set_reverb_filter_coeff(newval);
479 }
480 else
481 {
482 if (field == DAC_REVERB_FEEDBACK)
483 {
484 if (global_rev)
485 set_reverb_comb_factors(newval);
486 }
487 else
488 {
489 int i;
490 for (i = 0; i <= max_active_slot; i++)
491 {
492 dac_info *dp;
493 dp = play_list[i];
494 if ((dp) && ((!sp) || (sp == dp->sp)))
495 {
496 int val;
497 switch (field)
498 {
499 case DAC_EXPAND:
500 if (dp->spd)
501 mus_set_increment(dp->spd->gen, newval);
502 break;
503
504 case DAC_EXPAND_LENGTH: /* segment length */
505 if (dp->spd)
506 {
507 val = (int)(snd_srate(sp) * newval);
508 mus_set_length(dp->spd->gen, val);
509 mus_set_ramp(dp->spd->gen, (int)(val * sp->expand_control_ramp));
510 }
511 break;
512
513 case DAC_EXPAND_RAMP:
514 if (dp->spd)
515 {
516 val = (int)(newval * sp->expand_control_length * snd_srate(sp));
517 mus_set_ramp(dp->spd->gen, val);
518 }
519 break;
520
521 case DAC_EXPAND_HOP: /* output hop */
522 if (dp->spd)
523 {
524 val = (int)(snd_srate(sp) * newval);
525 mus_set_hop(dp->spd->gen, val);
526 mus_set_increment(dp->spd->gen, sp->expand_control);
527 }
528 break;
529
530 case DAC_EXPAND_SCALER:
531 if (dp->spd)
532 mus_set_scaler(dp->spd->gen, newval);
533 break;
534
535 case DAC_CONTRAST_AMP:
536 dp->contrast_amp = newval;
537 break;
538
539 default:
540 break;
541 }
542 }
543 }
544 }
545 }
546 }
547 }
548
549
dac_set_expand(snd_info * sp,mus_float_t newval)550 void dac_set_expand(snd_info *sp, mus_float_t newval) {dac_set_field(sp, newval, DAC_EXPAND);}
dac_set_expand_length(snd_info * sp,mus_float_t newval)551 void dac_set_expand_length(snd_info *sp, mus_float_t newval) {dac_set_field(sp, newval, DAC_EXPAND_LENGTH);}
dac_set_expand_ramp(snd_info * sp,mus_float_t newval)552 void dac_set_expand_ramp(snd_info *sp, mus_float_t newval) {dac_set_field(sp, newval, DAC_EXPAND_RAMP);}
dac_set_expand_hop(snd_info * sp,mus_float_t newval)553 void dac_set_expand_hop(snd_info *sp, mus_float_t newval) {dac_set_field(sp, newval, DAC_EXPAND_HOP);}
554 /* static void dac_set_expand_scaler(snd_info *sp, mus_float_t newval) {dac_set_field(sp, newval, DAC_EXPAND_SCALER);} */ /* not currently accessible */
dac_set_contrast_amp(snd_info * sp,mus_float_t newval)555 void dac_set_contrast_amp(snd_info *sp, mus_float_t newval) {dac_set_field(sp, newval, DAC_CONTRAST_AMP);}
dac_set_reverb_feedback(snd_info * sp,mus_float_t newval)556 void dac_set_reverb_feedback(snd_info *sp, mus_float_t newval) {dac_set_field(sp, newval, DAC_REVERB_FEEDBACK);}
dac_set_reverb_lowpass(snd_info * sp,mus_float_t newval)557 void dac_set_reverb_lowpass(snd_info *sp, mus_float_t newval) {dac_set_field(sp, newval, DAC_REVERB_LOWPASS);}
558
559
560
561 /* -------------------------------- stop playing (remove from play-list) -------------------------------- */
562
563 typedef struct {
564 int srate; /* output srate */
565 int channels; /* total output channels currently active */
566 int framples; /* samples per channel per output block */
567 int devices; /* output devices active */
568 int *chans_per_device; /* channels sent to each active device */
569 mus_sample_t out_samp_type; /* output sample type */
570 int slice; /* background process state (i.e. starting, running, quitting) */
571 mus_long_t reverb_ring_framples; /* how long the reverb rings after the end (if reverb, of course) */
572
573 } dac_state;
574
575 static dac_state *snd_dacp = NULL;
576
free_dac_state(void)577 static void free_dac_state(void)
578 {
579 if (snd_dacp)
580 {
581 if (snd_dacp->chans_per_device) free(snd_dacp->chans_per_device);
582 free(snd_dacp);
583 snd_dacp = NULL;
584 }
585 }
586
587 static bool dac_running = false;
588 static Xen play_hook;
589 static Xen start_playing_hook;
590 static Xen stop_playing_hook;
591 static Xen stop_playing_selection_hook;
592 static Xen start_playing_selection_hook;
593
594
595 #define MAX_DEVICES 8
596 static int dev_fd[MAX_DEVICES] = {-1, -1, -1, -1, -1, -1, -1, -1};
597
cleanup_dac(void)598 void cleanup_dac(void)
599 {
600 /* called only from snd_exit_cleanly in snd-main.c */
601 int i;
602 if (dac_running)
603 for (i = 0; i < MAX_DEVICES; i++)
604 if (dev_fd[i] != -1)
605 {
606 mus_audio_close(dev_fd[i]);
607 dev_fd[i] = -1;
608 }
609 for (i = 0; i < MAX_DEVICES; i++) dev_fd[i] = -1;
610 dac_running = false;
611 }
612
613
something_is_playing(void)614 static bool something_is_playing(void)
615 {
616 int i;
617 if (play_list)
618 for (i = 0; i < dac_max_sounds; i++)
619 if (play_list[i]) return(true);
620 return(false);
621 }
622
623
reflect_play_stop(snd_info * sp)624 static void reflect_play_stop(snd_info *sp)
625 {
626 #if (!USE_NO_GUI)
627 set_control_panel_play_button(sp);
628 #endif
629 set_open_file_play_button(false);
630 #if (!USE_NO_GUI)
631 view_files_unplay();
632 #endif
633 if (!something_is_playing())
634 ss->tracking = false;
635 }
636
637
638 static void free_player_sound(snd_info *sp);
639
640 typedef enum {WITHOUT_TOGGLE, WITH_TOGGLE} dac_toggle_t;
641
stop_playing_with_toggle(dac_info * dp,dac_toggle_t toggle,with_hook_t with_hook,play_stop_t reason)642 static void stop_playing_with_toggle(dac_info *dp, dac_toggle_t toggle, with_hook_t with_hook, play_stop_t reason)
643 {
644 snd_info *sp = NULL;
645 bool sp_stopping = false;
646
647 if ((!dp) || (!play_list)) return;
648 sp = dp->sp;
649 if ((sp) && (sp->inuse != SOUND_IDLE))
650 {
651 if (sp->playing > 0) sp->playing--;
652 if (sp->playing == 0) sp_stopping = true;
653
654 if ((sp_stopping) &&
655 (ss->tracking) &&
656 (sp->inuse == SOUND_NORMAL) &&
657 (sp->index >= 0))
658 {
659 uint32_t i;
660 for (i = 0; i < sp->nchans; i++)
661 {
662 chan_info *cp;
663 cp = sp->chans[i];
664 if ((cp == dp->cp) ||
665 (sp->sync != 0)) /* don't move the cursor in a channel that isn't playing */
666 {
667 if (with_tracking_cursor(ss) == TRACK_AND_STAY)
668 {
669 if (dp->cur_srate > 0.0)
670 {
671 mus_long_t samp;
672 samp = current_location(dp->chn_fd) + ((snd_dacp) ? snd_dacp->framples : 0);
673 if (dp->selection)
674 {
675 if (samp > selection_end(cp))
676 samp = selection_end(cp);
677 }
678 else
679 {
680 if (samp > current_samples(cp))
681 samp = current_samples(cp);
682 }
683 cursor_sample(cp) = samp - 1;
684 }
685 cp->original_left_sample = cursor_sample(cp) - (cp->original_window_size / 2);
686 if (cp->original_left_sample < 0)
687 cp->original_left_sample = 0;
688 }
689 else cursor_sample(cp) = cp->original_cursor;
690 cursor_moveto_with_window(cp, cursor_sample(cp), cp->original_left_sample, cp->original_window_size);
691 update_graph(cp);
692 }
693 }
694 }
695 /* if ctrl-click play, c-t, c-q -> this flag is still set from aborted previous play, so clear at c-t (or c-g) */
696 }
697 else sp = NULL; /* don't free it as a player below */
698 play_list[dp->slot] = NULL;
699 play_list_members--;
700
701 if (toggle == WITH_TOGGLE)
702 {
703 switch (dp->type)
704 {
705 case DAC_CHANNEL:
706 if ((sp) && (sp->playing <= 0))
707 reflect_play_stop(sp);
708 break;
709 case DAC_REGION:
710 if (dp->region != INVALID_REGION)
711 reflect_play_region_stop(dp->region);
712 break;
713 case DAC_MIX:
714 if (dp->mix_id != INVALID_MIX_ID)
715 reflect_mix_play_stop();
716 case DAC_XEN:
717 break;
718 case DAC_NOTHING:
719 break;
720 }
721 }
722
723 if (dp->slot == max_active_slot) max_active_slot--;
724 if (with_hook == WITH_HOOK)
725 {
726 if (dp->type == DAC_CHANNEL)
727 {
728 if (dp->selection)
729 {
730 reflect_play_selection_stop();
731 if (Xen_hook_has_list(stop_playing_selection_hook))
732 run_hook(stop_playing_selection_hook,
733 Xen_empty_list,
734 S_stop_playing_selection_hook);
735 }
736 else
737 {
738 if ((sp_stopping) && (Xen_hook_has_list(stop_playing_hook)))
739 run_hook(stop_playing_hook,
740 Xen_list_1(C_int_to_Xen_sound(sp->index)),
741 S_stop_playing_hook);
742 }
743 }
744 }
745
746 if ((sp) && (is_player_sound(sp)))
747 {
748 int k;
749 bool free_ok = true;
750 dp->sp = NULL; /* free_player_sound frees it */
751 for (k = dp->slot + 1; k < dac_max_sounds; k++)
752 {
753 dac_info *ndp;
754 ndp = play_list[k];
755 if ((ndp) &&
756 (ndp->sp) &&
757 (ndp->sp == sp))
758 {
759 free_ok = false;
760 break;
761 }
762 }
763 if (free_ok)
764 free_player_sound(sp);
765 sp = NULL;
766 }
767 free_dac_info(dp, reason); /* this will call the stop-function, if any */
768
769 if ((sp) && (sp_stopping) && (sp->delete_me))
770 {
771 #if USE_MOTIF
772 if (sp->delete_me != (void *)1)
773 clear_deleted_snd_info(sp->delete_me); /* for various file dialog play buttons */
774 #endif
775 completely_free_snd_info(sp); /* dummy snd_info struct for (play "filename") in snd-xen.c */
776 }
777 }
778
779
stop_playing(dac_info * dp,with_hook_t with_hook,play_stop_t reason)780 static void stop_playing(dac_info *dp, with_hook_t with_hook, play_stop_t reason)
781 {
782 stop_playing_with_toggle(dp, WITH_TOGGLE, with_hook, reason);
783 }
784
785
786 static idle_func_t dac_in_background(any_pointer_t ptr);
787 static idle_func_t dac_work_proc = 0;
788
789
stop_playing_sound_with_toggle(snd_info * sp,dac_toggle_t toggle,with_hook_t with_hook,play_stop_t reason)790 static void stop_playing_sound_with_toggle(snd_info *sp, dac_toggle_t toggle, with_hook_t with_hook, play_stop_t reason)
791 {
792 /* this needs to scan all current play_list members and remove any that are referring
793 * to sp, even indirectly (as through the current selection)
794 */
795
796 /* if reason = PLAY_STOP_CALLED, PLAY_C_T, or PLAY_C_G, we need to slam the output volumes to 0.0 (so the
797 * draining output is not played), then once we're sure output has stopped, put them back where they were.
798 * But, this action is sound-driver (OS) specific -- perhaps just hit MUS_AUDIO_AMP and hope?
799 * How to tell that on-card buffers are finally empty? Wait 1 or 2 seconds?
800 *
801 * an added annoyance -- to get current amps, we have to make separate read call for each chan!
802 */
803
804 if ((sp) && (play_list))
805 {
806 int i;
807 dac_info *dp;
808 for (i = 0; i < dac_max_sounds; i++)
809 if ((play_list[i]) &&
810 (sp == (play_list[i]->sp)))
811 {
812 dp = play_list[i];
813 play_list[i] = NULL;
814 stop_playing_with_toggle(dp, toggle, with_hook, reason);
815 }
816 if ((play_list_members > 0) && (with_hook == WITH_HOOK))
817 {
818 /* see comment below */
819 for (i = 0; i < dac_max_sounds; i++)
820 if ((play_list[i]) &&
821 (sp == (play_list[i]->sp)))
822 {
823 dp = play_list[i];
824 play_list[i] = NULL;
825 stop_playing_with_toggle(dp, toggle, WITHOUT_HOOK, reason); /* do it again but with hook disabled */
826 }
827 }
828 }
829 }
830
831
stop_playing_sound(snd_info * sp,play_stop_t reason)832 void stop_playing_sound(snd_info *sp, play_stop_t reason)
833 {
834 stop_playing_sound_with_toggle(sp, WITH_TOGGLE, WITH_HOOK, reason);
835 }
836
837
stop_playing_sound_without_hook(snd_info * sp,play_stop_t reason)838 void stop_playing_sound_without_hook(snd_info *sp, play_stop_t reason)
839 {
840 stop_playing_sound_with_toggle(sp, WITH_TOGGLE, WITHOUT_HOOK, reason);
841 }
842
843
stop_playing_sound_no_toggle(snd_info * sp,play_stop_t reason)844 void stop_playing_sound_no_toggle(snd_info *sp, play_stop_t reason)
845 {
846 stop_playing_sound_with_toggle(sp, WITHOUT_TOGGLE, WITH_HOOK, reason);
847 }
848
849
stop_playing_all_sounds_1(with_hook_t with_hook,play_stop_t reason)850 static void stop_playing_all_sounds_1(with_hook_t with_hook, play_stop_t reason)
851 {
852 if (play_list)
853 {
854 int i;
855 dac_info *dp;
856 for (i = 0; i < dac_max_sounds; i++)
857 {
858 dp = play_list[i];
859 play_list[i] = NULL;
860 stop_playing(dp, with_hook, reason);
861 /* this can call stop_playing_hook which can make a new play_list member where the old one used to be! */
862 }
863 if ((play_list_members > 0) && (with_hook == WITH_HOOK))
864 {
865 /* stop-playing-hook must have started a new player, but in this case,
866 * the rest of Snd assumes the dac has stopped no matter what. So,
867 * we make a second pass with the hooks disabled.
868 */
869 for (i = 0; i < dac_max_sounds; i++)
870 {
871 dp = play_list[i];
872 play_list[i] = NULL;
873 stop_playing(dp, WITHOUT_HOOK, reason);
874 }
875 }
876 }
877 if (snd_dacp)
878 {
879 snd_dacp->slice = 2;
880 dac_in_background(NULL); /* try to force completion (work proc might not be called above) */
881 }
882 }
883
884
stop_playing_all_sounds(play_stop_t reason)885 void stop_playing_all_sounds(play_stop_t reason)
886 {
887 stop_playing_all_sounds_1(WITH_HOOK, reason);
888 }
889
890
stop_playing_all_sounds_without_hook(play_stop_t reason)891 static void stop_playing_all_sounds_without_hook(play_stop_t reason)
892 {
893 stop_playing_all_sounds_1(WITHOUT_HOOK, reason);
894 }
895
896
stop_playing_region(int n,play_stop_t reason)897 void stop_playing_region(int n, play_stop_t reason)
898 {
899 if (play_list)
900 {
901 int i;
902 dac_info *dp;
903 for (i = 0; i < dac_max_sounds; i++)
904 if ((play_list[i]) &&
905 (play_list[i]->type == DAC_REGION) &&
906 (play_list[i]->region == n))
907 {
908 dp = play_list[i];
909 play_list[i] = NULL;
910 stop_playing(dp, WITHOUT_HOOK, reason);
911 }
912 }
913 }
914
915
916 /* -------------------------------- play (add to play-list) -------------------------------- */
917
find_slot_to_play(void)918 static int find_slot_to_play(void)
919 {
920 int i, old_size;
921
922 if (!play_list)
923 {
924 dac_max_sounds = INITIAL_MAX_SOUNDS;
925 play_list = (dac_info **)calloc(dac_max_sounds, sizeof(dac_info *));
926 }
927
928 for (i = 0; i < dac_max_sounds; i++)
929 if (!play_list[i])
930 return(i);
931
932 old_size = dac_max_sounds;
933 dac_max_sounds += INITIAL_MAX_SOUNDS;
934 play_list = (dac_info **)realloc(play_list, dac_max_sounds * sizeof(dac_info *));
935 for (i = old_size; i < dac_max_sounds; i++) play_list[i] = NULL;
936
937 return(old_size);
938 }
939
940
make_dac_info(int slot,chan_info * cp,snd_info * sp,snd_fd * fd,mus_long_t end,int out_chan,dac_source_t type,Xen func)941 static dac_info *make_dac_info(int slot, chan_info *cp, snd_info *sp, snd_fd *fd, mus_long_t end, int out_chan, dac_source_t type, Xen func)
942 {
943 dac_info *dp;
944
945 dp = (dac_info *)calloc(1, sizeof(dac_info)); /* only place dac_info is created */
946 dp->stop_procedure = Xen_false;
947 dp->stop_procedure_gc_loc = NOT_A_GC_LOC;
948 dp->region = INVALID_REGION;
949 dp->mix_id = INVALID_MIX_ID;
950 dp->direction = 1;
951 dp->type = type; /* dac needs to know how to get input before calling mus_make_src below */
952 if (type == DAC_NOTHING)
953 dp->dac_sample = dac_no_sample;
954 else
955 {
956 if (type == DAC_XEN)
957 {
958 dp->dac_sample = dac_xen_sample;
959 dp->func = func;
960 dp->func_gc_loc = snd_protect(func);
961 }
962 else
963 {
964 dp->dac_sample = dac_read_sample;
965 dp->func = Xen_false;
966 dp->func_gc_loc = NOT_A_GC_LOC;
967 }
968 }
969 dp->a = NULL;
970 dp->a_size = 0;
971 dp->audio_chan = out_chan;
972 dp->never_sped = true;
973 dp->chn_fd = fd;
974 dp->sp = sp;
975 dp->cp = cp;
976
977 /* next block may get input */
978 if (sp)
979 {
980 dp->expanding = sp->expand_control_on;
981 dp->filtering = ((sp->filter_control_on) && (sp->filter_control_order > 0));
982 dp->reverbing = sp->reverb_control_on;
983 dp->contrast_amp = sp->contrast_control_amp;
984
985 if ((!(snd_feq(sp->speed_control, 1.0))) ||
986 (sp->speed_control_direction == -1))
987 {
988 dp->src = mus_make_src(&dac_src_input_as_needed, sp->speed_control, sinc_width(ss), (void *)dp);
989 dp->direction = sp->speed_control_direction;
990 }
991
992 if (dp->expanding)
993 {
994 dp->spd = (spd_info *)make_expand(sp, sp->expand_control, dp);
995 dp->expand_ring_framples = (int)(snd_srate(sp) * sp->expand_control * sp->expand_control_length * 2);
996 }
997
998 if (dp->filtering)
999 {
1000 sp->filter_control_changed = false;
1001 if (!(sp->filter_control_envelope))
1002 dp->filtering = false;
1003 else
1004 {
1005 mus_float_t *data;
1006 data = sample_linear_env(sp->filter_control_envelope, sp->filter_control_order);
1007 if (data)
1008 {
1009 dp->flt = make_flt(dp, sp->filter_control_order, data);
1010 free(data);
1011 }
1012 else dp->filtering = false;
1013 }
1014 }
1015 }
1016
1017 play_list_members++;
1018 dp->end = end;
1019 play_list[slot] = dp;
1020 dp->slot = slot;
1021 if (max_active_slot < slot) max_active_slot = slot;
1022 if (sp)
1023 {
1024 dp->cur_srate = sp->speed_control * sp->speed_control_direction;
1025 if (!(snd_feq(dp->cur_srate, 1.0))) dp->never_sped = false;
1026 dp->cur_amp = AMP_CONTROL(sp, dp);
1027 dp->cur_index = sp->contrast_control;
1028 dp->cur_exp = sp->expand_control;
1029 dp->cur_rev = sp->reverb_control_scale;
1030 }
1031
1032 return(dp);
1033 }
1034
1035
start_dac(int srate,int channels,play_process_t background,mus_float_t decay)1036 static void start_dac(int srate, int channels, play_process_t background, mus_float_t decay)
1037 {
1038 int i;
1039 /* look for channel folding cases etc */
1040 /* channels = how many output audio chans we have; dac_combines_channels sets whether to wrap or muffle chans outside this limit */
1041
1042 if (with_tracking_cursor(ss) != DONT_TRACK)
1043 ss->tracking = true;
1044
1045 for (i = 0; i <= max_active_slot; i++)
1046 {
1047 dac_info *dp;
1048 dp = play_list[i];
1049 if ((dp) && (dac_running)) /* dac_running also if apply */
1050 {
1051 /* in the "normal" (non-apply) case the reverb allocation is deferred until we're sure about the number of output channels */
1052 if ((dp->reverbing) &&
1053 (dp->sp) &&
1054 (!global_rev))
1055 make_reverb(dp->sp, channels);
1056 if (snd_dacp)
1057 {
1058 if (dp->audio_chan >= snd_dacp->channels) /* if dac_running, the number of channels has already been set and won't change */
1059 {
1060 if (dac_combines_channels(ss))
1061 dp->audio_chan %= snd_dacp->channels;
1062 else stop_playing(dp, WITHOUT_HOOK, PLAY_NO_CHANNEL);
1063 }
1064 }
1065 }
1066 }
1067 /* any number of sounds can be piling into the dac buffers with new ones added at any time
1068 * (this is the play_list -- an array of dac_info pointers, each one a separate channel rendition)
1069 */
1070 if (!dac_running)
1071 {
1072 if (snd_dacp) free_dac_state();
1073 snd_dacp = (dac_state *)calloc(1, sizeof(dac_state));
1074 snd_dacp->slice = 0;
1075 snd_dacp->srate = srate;
1076 snd_dacp->out_samp_type = MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE;
1077 if (snd_dacp->srate <= 0) snd_dacp->srate = 44100;
1078 snd_dacp->channels = channels;
1079 if (dac_size(ss) > 0)
1080 snd_dacp->framples = dac_size(ss);
1081 else snd_dacp->framples = 256;
1082 snd_dacp->devices = 1; /* just a first guess */
1083 snd_dacp->reverb_ring_framples = (mus_long_t)(srate * decay);
1084 if (background == IN_BACKGROUND)
1085 dac_work_proc = BACKGROUND_ADD(dac_in_background, NULL);
1086 else
1087 {
1088 /* here we want to play as an atomic (not background) action */
1089 while (dac_in_background(NULL) == BACKGROUND_CONTINUE)
1090 check_for_event(); /* need to be able to C-g out of this */
1091 }
1092 }
1093 }
1094
1095
1096 /* pos = to_c_edit_position(cp, edpos, caller, arg_pos); */
1097
add_channel_to_play_list(chan_info * cp,snd_info * sp,mus_long_t start,mus_long_t end,int pos,int out_chan)1098 static dac_info *add_channel_to_play_list(chan_info *cp, snd_info *sp, mus_long_t start, mus_long_t end, int pos, int out_chan)
1099 {
1100 /* if not sp, control panel is ignored */
1101 int slot;
1102 read_direction_t direction = READ_FORWARD;
1103 mus_long_t beg = 0;
1104 snd_fd *sf;
1105
1106 if (pos == AT_CURRENT_EDIT_POSITION) pos = cp->edit_ctr;
1107 if (sp)
1108 {
1109 if (sp->speed_control_direction == 1)
1110 {
1111 if (start >= cp->edits[pos]->samples) return(NULL);
1112 direction = READ_FORWARD;
1113 beg = start;
1114 }
1115 else
1116 {
1117 direction = READ_BACKWARD;
1118 if (start < end)
1119 {
1120 mus_long_t tmp;
1121 tmp = start;
1122 start = end;
1123 end = tmp;
1124 }
1125 if ((start == 0) || (start >= cp->edits[pos]->samples)) /* don't be pedantic about the start point */
1126 beg = cp->edits[pos]->samples - 1;
1127 else beg = start;
1128 if ((end == 0) || (end >= (cp->edits[pos]->samples)))
1129 end = NO_END_SPECIFIED;
1130 }
1131 }
1132
1133 slot = find_slot_to_play();
1134 if (slot == -1) return(NULL);
1135
1136 sf = init_sample_read_any(beg, cp, direction, pos);
1137 if (sf)
1138 {
1139 if (sp)
1140 {
1141 sp->playing++;
1142 if (((with_tracking_cursor(ss) != DONT_TRACK) || (ss->tracking)) &&
1143 (!(is_player_sound(sp))) &&
1144 (sp->inuse == SOUND_NORMAL))
1145 {
1146 cp->original_cursor = cursor_sample(cp);
1147 if (cp->axis)
1148 {
1149 cp->original_left_sample = cp->axis->losamp;
1150 cp->original_window_size = cp->axis->hisamp - cp->axis->losamp;
1151 }
1152 cp->cursor_on = true;
1153 cursor_moveto_without_verbosity(cp, start);
1154 #if USE_MOTIF
1155 if (cp->widgets)
1156 update_graph(cp);
1157 #endif
1158 }
1159 }
1160 return(make_dac_info(slot, cp, sp, sf, end, out_chan, DAC_CHANNEL, Xen_false));
1161 }
1162 return(NULL);
1163 }
1164
1165
add_region_channel_to_play_list(int region,int chan,mus_long_t beg,mus_long_t end,int out_chan)1166 static dac_info *add_region_channel_to_play_list(int region, int chan, mus_long_t beg, mus_long_t end, int out_chan)
1167 {
1168 int slot;
1169 snd_fd *fd;
1170
1171 slot = find_slot_to_play();
1172 if (slot == -1) return(NULL);
1173
1174 fd = init_region_read(beg, region, chan, READ_FORWARD);
1175 if (fd)
1176 {
1177 dac_info *dp;
1178 dp = make_dac_info(slot, fd->cp, NULL, fd, end, out_chan, DAC_REGION, Xen_false);
1179 if (dp) dp->region = region;
1180 return(dp);
1181 }
1182 return(NULL);
1183 }
1184
1185
play_region_1(int region,play_process_t background,Xen stop_proc)1186 void play_region_1(int region, play_process_t background, Xen stop_proc)
1187 {
1188 /* just plays region (not current selection) -- no control panel etc */
1189 int chans, i;
1190 dac_info *dp = NULL, *rtn_dp = NULL;
1191
1192 if ((background == NOT_IN_BACKGROUND) && (play_list_members > 0)) return;
1193 if (!(region_ok(region))) return;
1194 chans = region_chans(region);
1195 if (chans == 0) return;
1196
1197 for (i = 0; i < chans; i++)
1198 {
1199 dp = add_region_channel_to_play_list(region, i, 0, NO_END_SPECIFIED, i); /* i = out chan */
1200 if (dp)
1201 {
1202 if (!rtn_dp) rtn_dp = dp;
1203 }
1204 }
1205 if (rtn_dp)
1206 {
1207 rtn_dp->stop_procedure = stop_proc;
1208 if (Xen_is_procedure(stop_proc))
1209 rtn_dp->stop_procedure_gc_loc = snd_protect(stop_proc);
1210 start_dac(region_srate(region), chans, background, DEFAULT_REVERB_CONTROL_DECAY);
1211 }
1212 }
1213
1214
play_region(int region,play_process_t background)1215 void play_region(int region, play_process_t background)
1216 {
1217 play_region_1(region, background, Xen_false);
1218 }
1219
1220
add_mix_to_play_list(mix_state * ms,chan_info * cp,mus_long_t beg_within_mix,bool start_playing)1221 bool add_mix_to_play_list(mix_state *ms, chan_info *cp, mus_long_t beg_within_mix, bool start_playing)
1222 {
1223 int slot;
1224 slot = find_slot_to_play();
1225 if (slot != -1)
1226 {
1227 snd_fd *fd;
1228 fd = make_virtual_mix_reader(cp, beg_within_mix, ms->len - beg_within_mix, ms->index, 1.0, READ_FORWARD);
1229 if (fd)
1230 {
1231 dac_info *dp;
1232 dp = make_dac_info(slot, cp, NULL, fd, NO_END_SPECIFIED, 0, DAC_MIX, Xen_false);
1233 if (dp)
1234 {
1235 dp->mix_id = ms->index; /* any valid mix id will do */
1236 if (start_playing)
1237 start_dac(snd_srate(cp->sound), 1, NOT_IN_BACKGROUND, DEFAULT_REVERB_CONTROL_DECAY);
1238 return(true);
1239 }
1240 }
1241 else free_snd_fd(fd);
1242 }
1243 return(false);
1244 }
1245
1246
1247 /* (play (let ((osc (make-oscil 440.0))
1248 (samp 0))
1249 (lambda ()
1250 (if (> samp 20000)
1251 #f
1252 (begin
1253 (set! samp (+ samp 1))
1254 (* .5 (oscil osc))))))) ; you can use explicit control panel accessors
1255 */
1256
add_zeros_to_play_list(int srate,int chans)1257 static bool add_zeros_to_play_list(int srate, int chans)
1258 {
1259 int slot;
1260 slot = find_slot_to_play();
1261 if (slot != -1)
1262 {
1263 dac_info *dp;
1264 dp = make_dac_info(slot, NULL, NULL, NULL, NO_END_SPECIFIED, 0, DAC_NOTHING, Xen_false);
1265 if (dp)
1266 {
1267 start_dac(srate, chans, IN_BACKGROUND, DEFAULT_REVERB_CONTROL_DECAY);
1268 return(true);
1269 }
1270 }
1271 return(false);
1272 }
1273
1274
add_xen_to_play_list(Xen func)1275 static bool add_xen_to_play_list(Xen func)
1276 {
1277 int slot;
1278 slot = find_slot_to_play();
1279 if (slot != -1)
1280 {
1281 dac_info *dp;
1282 dp = make_dac_info(slot, NULL, NULL, NULL, NO_END_SPECIFIED, 0, DAC_XEN, func);
1283 if (dp)
1284 {
1285 #if USE_NO_GUI
1286 start_dac((int)mus_srate(), 1, NOT_IN_BACKGROUND, DEFAULT_REVERB_CONTROL_DECAY);
1287 #else
1288 start_dac((int)mus_srate(), 1, IN_BACKGROUND, DEFAULT_REVERB_CONTROL_DECAY);
1289 #endif
1290 /* ^ output channels */
1291 return(true);
1292 }
1293 }
1294 return(false);
1295 }
1296
1297
call_start_playing_hook(snd_info * sp)1298 static bool call_start_playing_hook(snd_info *sp)
1299 {
1300 if ((Xen_hook_has_list(start_playing_hook)) &&
1301 (Xen_is_true(run_or_hook(start_playing_hook,
1302 Xen_list_1(C_int_to_Xen_sound(sp->index)), /* this can be 123456 (TEMP_SOUND_INDEX in snd-file.c) -- View:Files dialog play button */
1303 S_start_playing_hook))))
1304 {
1305 reflect_play_stop(sp); /* turns off buttons */
1306 if (sp->delete_me)
1307 completely_free_snd_info(sp); /* dummy snd_info struct for (play "filename") in snd-xen.c */
1308 return(true);
1309 }
1310 return(false);
1311 }
1312
1313
call_start_playing_selection_hook(void)1314 static bool call_start_playing_selection_hook(void)
1315 {
1316 return((Xen_hook_has_list(start_playing_selection_hook)) &&
1317 (Xen_is_true(run_or_hook(start_playing_selection_hook,
1318 Xen_empty_list,
1319 S_start_playing_selection_hook))));
1320 }
1321
1322
play_channel_1(chan_info * cp,mus_long_t start,mus_long_t end,play_process_t background,int pos,Xen stop_proc,int out_chan)1323 static dac_info *play_channel_1(chan_info *cp, mus_long_t start, mus_long_t end, play_process_t background,
1324 int pos, Xen stop_proc, int out_chan)
1325 {
1326 /* just plays one channel (ignores possible sync), includes start-hook */
1327 snd_info *sp;
1328 dac_info *dp = NULL;
1329
1330 sp = cp->sound;
1331 if (sp->inuse == SOUND_IDLE) return(NULL);
1332 if (call_start_playing_hook(sp)) return(NULL);
1333
1334 dp = add_channel_to_play_list(cp, sp, start, end, pos, out_chan);
1335 if (dp)
1336 {
1337 dp->stop_procedure = stop_proc;
1338 if (Xen_is_procedure(stop_proc))
1339 dp->stop_procedure_gc_loc = snd_protect(stop_proc);
1340 set_play_button(sp, true);
1341 start_dac(snd_srate(sp), 1, background, sp->reverb_control_decay);
1342 }
1343 return(dp);
1344 }
1345
1346
play_channel(chan_info * cp,mus_long_t start,mus_long_t end)1347 void play_channel(chan_info *cp, mus_long_t start, mus_long_t end)
1348 {
1349 play_channel_1(cp, start, end, IN_BACKGROUND, AT_CURRENT_EDIT_POSITION, Xen_false, cp->chan);
1350 }
1351
1352
play_sound_1(snd_info * sp,mus_long_t start,mus_long_t end,play_process_t background,Xen edpos,Xen stop_proc,const char * caller,int arg_pos)1353 static dac_info *play_sound_1(snd_info *sp, mus_long_t start, mus_long_t end, play_process_t background,
1354 Xen edpos, Xen stop_proc, const char *caller, int arg_pos)
1355 {
1356 /* just plays one sound (ignores possible sync) */
1357 uint32_t i;
1358 dac_info *dp = NULL, *rtn_dp = NULL;
1359
1360 if ((background == NOT_IN_BACKGROUND) &&
1361 (play_list_members > 0))
1362 return(NULL);
1363 if (sp->inuse == SOUND_IDLE) return(NULL);
1364 if (call_start_playing_hook(sp)) return(NULL);
1365 for (i = 0; i < sp->nchans; i++)
1366 {
1367 int pos;
1368 pos = to_c_edit_position(sp->chans[i], edpos, caller, arg_pos);
1369 dp = add_channel_to_play_list(sp->chans[i], sp, start, end, pos, i); /* i = out chan */
1370 if ((dp) && (!rtn_dp)) rtn_dp = dp;
1371 }
1372 if (rtn_dp)
1373 {
1374 rtn_dp->stop_procedure = stop_proc;
1375 if (Xen_is_procedure(stop_proc))
1376 rtn_dp->stop_procedure_gc_loc = snd_protect(stop_proc);
1377 set_play_button(sp, true);
1378 start_dac(snd_srate(sp), sp->nchans, background, sp->reverb_control_decay);
1379 }
1380 return(rtn_dp);
1381 }
1382
1383
play_sound(snd_info * sp,mus_long_t start,mus_long_t end)1384 void play_sound(snd_info *sp, mus_long_t start, mus_long_t end)
1385 {
1386 play_sound_1(sp, start, end, IN_BACKGROUND, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), Xen_false, NULL, 0);
1387 }
1388
1389
play_channels_1(chan_info ** cps,int chans,mus_long_t * starts,mus_long_t * ur_ends,play_process_t background,Xen edpos,bool selection,Xen stop_proc,const char * caller,int arg_pos)1390 static dac_info *play_channels_1(chan_info **cps, int chans, mus_long_t *starts, mus_long_t *ur_ends, play_process_t background,
1391 Xen edpos, bool selection, Xen stop_proc, const char *caller, int arg_pos)
1392 {
1393 /* ends can be NULL */
1394 int i;
1395 snd_info *sp = NULL;
1396 dac_info *dp = NULL, *rtn_dp = NULL;
1397 mus_long_t *ends;
1398
1399 if ((background == NOT_IN_BACKGROUND) &&
1400 (play_list_members > 0))
1401 return(NULL);
1402 if (chans <= 0) return(NULL);
1403
1404 if (!selection)
1405 {
1406 if (call_start_playing_hook(cps[0]->sound)) return(NULL);
1407 }
1408 else
1409 {
1410 if (call_start_playing_selection_hook()) return(NULL);
1411 }
1412
1413 if (ur_ends)
1414 ends = ur_ends;
1415 else
1416 {
1417 ends = (mus_long_t *)calloc(chans, sizeof(mus_long_t));
1418 for (i = 0; i < chans; i++)
1419 ends[i] = NO_END_SPECIFIED;
1420 }
1421
1422 sp = cps[0]->sound;
1423 for (i = 0; i < chans; i++)
1424 {
1425 int pos;
1426 pos = to_c_edit_position(cps[i], edpos, caller, arg_pos);
1427 dp = add_channel_to_play_list(cps[i], sp, starts[i], ends[i], pos, i);
1428 if (dp)
1429 {
1430 if (!rtn_dp) rtn_dp = dp;
1431 if (selection) dp->selection = true;
1432 }
1433 }
1434 if (!ur_ends) free(ends);
1435 if ((sp) && (rtn_dp))
1436 {
1437 rtn_dp->stop_procedure = stop_proc;
1438 if (Xen_is_procedure(stop_proc))
1439 rtn_dp->stop_procedure_gc_loc = snd_protect(stop_proc);
1440 set_play_button(sp, true);
1441 start_dac(snd_srate(sp), chans, background, sp->reverb_control_decay);
1442 }
1443 return(rtn_dp);
1444 }
1445
1446
play_channels(chan_info ** cps,int chans,mus_long_t * starts,mus_long_t * ur_ends,play_process_t background,Xen edpos,bool selection,const char * caller,int arg_pos)1447 void play_channels(chan_info **cps, int chans, mus_long_t *starts, mus_long_t *ur_ends,
1448 play_process_t background, Xen edpos, bool selection, const char *caller, int arg_pos)
1449 {
1450 play_channels_1(cps, chans, starts, ur_ends, background, edpos, selection, Xen_false, caller, arg_pos);
1451 }
1452
1453
play_channel_with_sync(chan_info * cp,mus_long_t start,mus_long_t end)1454 void play_channel_with_sync(chan_info *cp, mus_long_t start, mus_long_t end)
1455 {
1456 snd_info *sp;
1457 sync_info *si;
1458 mus_long_t *ends = NULL;
1459 int i;
1460
1461 sp = cp->sound;
1462 if ((sp->sync == 0) ||
1463 (is_player_sound(sp)))
1464 {
1465 play_channel(cp, start, end);
1466 return;
1467 }
1468
1469 si = snd_sync(sp->sync);
1470 if (end != NO_END_SPECIFIED)
1471 {
1472 ends = (mus_long_t *)calloc(si->chans, sizeof(mus_long_t));
1473 for (i = 0; i < si->chans; i++) ends[i] = end;
1474 }
1475 for (i = 0; i < si->chans; i++) si->begs[i] = start;
1476
1477 play_channels_1(si->cps, si->chans, si->begs, ends, IN_BACKGROUND, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), false, Xen_false, NULL, 0);
1478
1479 free_sync_info(si);
1480 if (ends) free(ends);
1481 }
1482
1483
play_selection_1(play_process_t background,Xen stop_proc)1484 static dac_info *play_selection_1(play_process_t background, Xen stop_proc)
1485 {
1486 /* just plays the current selection */
1487 dac_info *dp = NULL;
1488
1489 if (selection_is_active())
1490 {
1491 sync_info *si;
1492 si = selection_sync();
1493 if (si)
1494 {
1495 int i;
1496 mus_long_t *ends;
1497
1498 ends = (mus_long_t *)calloc(si->chans, sizeof(mus_long_t));
1499 for (i = 0; i < si->chans; i++)
1500 ends[i] = si->begs[i] + selection_len();
1501
1502 dp = play_channels_1(si->cps, si->chans, si->begs, ends, background, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), true, stop_proc, NULL, 0);
1503 /* dp->dac_sample is the reader */
1504 free_sync_info(si); /* does not free samplers */
1505 free(ends);
1506 }
1507 }
1508 return(dp);
1509 }
1510
1511
play_selection(play_process_t background)1512 void play_selection(play_process_t background)
1513 {
1514 play_selection_1(background, Xen_false);
1515 }
1516
1517
loop_play_selection(void)1518 void loop_play_selection(void)
1519 {
1520 play_selection_1(IN_BACKGROUND, Xen_true);
1521 }
1522
1523
1524 /* -------------------------------- process samples and write to DAC -------------------------------- */
1525
1526 #define NO_CHANGE 0
1527 #define JUST_AMP 1
1528 #define JUST_SPEED 2
1529 #define ALL_CHANGES 3
1530
choose_dac_op(dac_info * dp,snd_info * sp)1531 static int choose_dac_op(dac_info *dp, snd_info *sp)
1532 {
1533 if (!sp) return(NO_CHANGE);
1534 if ((dp->expanding) || (dp->filtering) || (dp->reverbing) || (sp->contrast_control_on))
1535 return(ALL_CHANGES);
1536 else
1537 {
1538 if ((sp->speed_control_direction != 1) || (!(snd_feq(sp->speed_control, 1.0))) || (!(snd_feq(dp->cur_srate, 1.0))))
1539 return(JUST_SPEED);
1540 else
1541 {
1542 if ((AMP_CONTROL(sp, dp) == dp->cur_amp) && (snd_feq(AMP_CONTROL(sp, dp), 1.0)))
1543 return(NO_CHANGE);
1544 else return(JUST_AMP);
1545 }
1546 }
1547 }
1548
1549 static int cursor_time;
1550 /* can't move cursor on each dac buffer -- causes clicks */
1551
1552 static bool dac_pausing = false;
1553
toggle_dac_pausing(void)1554 void toggle_dac_pausing(void) {dac_pausing = (!dac_pausing); play_button_pause(dac_pausing);} /* only below and snd-kbd.c */
play_in_progress(void)1555 bool play_in_progress(void) {return(play_list_members > 0);}
1556
1557
1558 static unsigned char **audio_bytes = NULL;
1559 static int audio_bytes_size = 0;
1560 static int audio_bytes_devices = 0;
1561
1562 static mus_float_t **dac_buffers = NULL;
1563 static int dac_buffer_size = 0;
1564 static int dac_buffer_chans = 0; /* chans allocated */
1565 static mus_float_t **rev_ins;
1566
1567 #define WRITE_TO_DAC 1
1568 #define WRITE_TO_FILE 0
1569
fill_dac_buffers(int write_ok)1570 static int fill_dac_buffers(int write_ok)
1571 {
1572 /* return value used only by Apply */
1573 int i;
1574 bool cursor_change = false;
1575 int framples;
1576 snd_info *sp;
1577
1578 framples = snd_dacp->framples;
1579 /* clear buffers */
1580 for (i = 0; i < snd_dacp->channels; i++)
1581 mus_clear_floats(dac_buffers[i], framples);
1582 if (global_rev)
1583 for (i = 0; i < snd_dacp->channels; i++)
1584 mus_clear_floats(rev_ins[i], framples);
1585
1586 if (dac_pausing)
1587 cursor_change = false;
1588 else
1589 {
1590 dac_info *dp;
1591 mus_float_t *buf;
1592 mus_float_t *revin;
1593
1594 if (Xen_hook_has_list(play_hook))
1595 run_hook(play_hook,
1596 Xen_list_1(C_int_to_Xen_integer(framples)),
1597 S_play_hook);
1598 cursor_time += framples;
1599 cursor_change = (cursor_time >= (int)(snd_dacp->srate * cursor_update_interval(ss)));
1600 /* the check for hooks and so on has to be separate from the fill loop to keep everything synchronized across stop-function replay requests etc */
1601
1602 /* first check for disasters (user closed sound while playing it or running Apply!) */
1603 for (i = 0; i <= max_active_slot; i++)
1604 {
1605 dp = play_list[i];
1606 if (dp)
1607 {
1608 sp = dp->sp; /* can be nil if region playing */
1609 if ((sp) && ((sp->inuse == SOUND_IDLE) || (sp->playing == 0)))
1610 stop_playing(dp, WITHOUT_HOOK, PLAY_CLOSE);
1611 }
1612 }
1613 /* now read currently active chans and update locations -- don't call any hooks or stop-functions! */
1614 for (i = 0; i <= max_active_slot; i++)
1615 {
1616 dp = play_list[i];
1617 if (dp)
1618 {
1619 int j;
1620 mus_float_t amp, incr, sr, sincr, ind, indincr, rev, revincr, fval;
1621 if (dp->audio_chan >= snd_dacp->channels) /* this can happen if we're playing 1 chan, try to add 2 chans */
1622 {
1623 if (dac_combines_channels(ss))
1624 dp->audio_chan %= snd_dacp->channels;
1625 else continue;
1626 }
1627
1628 /* check for moving cursor */
1629 sp = dp->sp; /* can be nil if region playing */
1630 if ((sp) &&
1631 (ss->tracking) &&
1632 (cursor_change) &&
1633 (dp->chn_fd) &&
1634 (!(dp->chn_fd->at_eof)) &&
1635 #if (!USE_NO_GUI)
1636 (dp->cp->widgets) && /* nil if play_file */
1637 #endif
1638 (dp->chn_fd->cb))
1639 {
1640 mus_long_t loc;
1641 bool old_just_zero;
1642 old_just_zero = dp->cp->just_zero;
1643 dp->cp->just_zero = true;
1644 loc = current_location(dp->chn_fd);
1645 loc -= (int)(cursor_location_offset(ss) * dp->cur_srate); /* should work in either direction */
1646 cursor_moveto_without_verbosity(dp->cp, loc);
1647 dp->cp->just_zero = old_just_zero;
1648 }
1649
1650 /* add a buffer's worth from the current source into dp->audio_chan */
1651 buf = dac_buffers[dp->audio_chan];
1652 if (!buf) continue;
1653 revin = rev_ins[dp->audio_chan];
1654 switch (choose_dac_op(dp, sp))
1655 {
1656 case NO_CHANGE:
1657 /* simplest case -- no changes at all */
1658 for (j = 0; j < framples; j++)
1659 buf[j] += (mus_float_t)((*(dp->dac_sample))(dp));
1660 break;
1661
1662 case JUST_AMP:
1663 /* AMP_CONTROL(sp, dp) is current UI value, dp->cur_amp is current local value */
1664 amp = dp->cur_amp;
1665 incr = (AMP_CONTROL(sp, dp) - amp) / (mus_float_t)(framples);
1666 for (j = 0; j < framples; j++, amp += incr)
1667 buf[j] += (mus_float_t)(amp * (*(dp->dac_sample))(dp));
1668 dp->cur_amp = amp;
1669 break;
1670
1671 case JUST_SPEED:
1672 /* includes amp changes */
1673 /* sp->speed_control is current UI value, dp->cur_srate is current local value */
1674 dp->never_sped = false;
1675 amp = dp->cur_amp;
1676 incr = (AMP_CONTROL(sp, dp) - amp) / (mus_float_t)(framples);
1677 sr = dp->cur_srate;
1678 sincr = (sp->speed_control * sp->speed_control_direction - sr) / (mus_float_t)(framples);
1679 if ((sr != 0.0) || (sincr != 0.0))
1680 {
1681 if (dp->src)
1682 {
1683 if ((amp == 1.0) && (incr == 0.0) && (sincr == 0.0))
1684 {
1685 mus_set_increment(dp->src, sr);
1686 mus_src_to_buffer(dp->src, &dac_src_input_as_needed, buf, framples);
1687 }
1688 else
1689 {
1690 for (j = 0; j < framples; j++, amp += incr, sr += sincr)
1691 {
1692 mus_set_increment(dp->src, sr);
1693 buf[j] += (amp * mus_src(dp->src, 0.0, &dac_src_input_as_needed));
1694 }
1695 }
1696 }
1697 else
1698 {
1699 for (j = 0; j < framples; j++, amp += incr, sr += sincr)
1700 buf[j] += (amp * speed(dp, sr));
1701 }
1702 }
1703 dp->cur_srate = sr;
1704 dp->cur_amp = amp;
1705 break;
1706
1707 case ALL_CHANGES:
1708 amp = dp->cur_amp;
1709 incr = (AMP_CONTROL(sp, dp) - amp) / (mus_float_t)(framples);
1710 sr = dp->cur_srate;
1711 sincr = (sp->speed_control * sp->speed_control_direction - sr) / (mus_float_t)(framples);
1712 if ((sincr != 0.0) || (!(snd_feq(sr, 1.0)))) dp->never_sped = false;
1713 ind = dp->cur_index;
1714 indincr = (sp->contrast_control - ind) / (mus_float_t)(framples);
1715 rev = dp->cur_rev;
1716 revincr = (sp->reverb_control_scale - rev) / (mus_float_t)(framples);
1717 if ((dp->filtering) && (sp->filter_control_changed))
1718 {
1719 mus_float_t *data;
1720 data = sample_linear_env(sp->filter_control_envelope, sp->filter_control_order);
1721 if (data)
1722 {
1723 /* check all chans in sp before clearing filter_order_changed flag */
1724 int j;
1725 for (j = i; j <= max_active_slot; j++)
1726 {
1727 dac_info *ndp;
1728 ndp = play_list[j];
1729 if ((ndp) &&
1730 (ndp->sp == sp) &&
1731 (ndp->filtering))
1732 {
1733 if (sp->filter_control_order > ndp->a_size) /* need more room in dp->a == flt->xcoeffs and flt->state */
1734 {
1735 free(ndp->a);
1736 ndp->a_size = sp->filter_control_order;
1737 ndp->a = (mus_float_t *)calloc(ndp->a_size, sizeof(mus_float_t));
1738 }
1739 mus_make_fir_coeffs(sp->filter_control_order, data, ndp->a); /* fill dp->a with new coeffs */
1740 mus_filter_set_xcoeffs(ndp->flt, ndp->a); /* tell gen about them */
1741 if (mus_filter_set_order(ndp->flt, sp->filter_control_order) < 0) /* fixup gen's order (and internal state array) */
1742 snd_warning("trouble in filter (order not changed?)");
1743 }
1744 }
1745 free(data);
1746 }
1747 sp->filter_control_changed = false;
1748 }
1749 if (dp->expanding)
1750 {
1751 mus_float_t ex, exincr;
1752 ex = dp->cur_exp;
1753 exincr = (sp->expand_control - ex) / (mus_float_t)(framples);
1754 for (j = 0; j < framples; j++, amp += incr, sr += sincr, ind += indincr, ex += exincr, rev += revincr)
1755 {
1756 fval = expand(dp, sr, ex);
1757 if (sp->contrast_control_on) fval = contrast(dp, amp, ind, fval); else fval *= amp;
1758 if (dp->filtering) fval = mus_fir_filter(dp->flt, fval);
1759 if (dp->reverbing) revin[j] += fval * rev;
1760 buf[j] += fval;
1761 }
1762 dp->cur_exp = ex;
1763 }
1764 else
1765 {
1766 if (dp->filtering)
1767 {
1768 for (j = 0; j < framples; j++, amp += incr, sr += sincr, ind += indincr, rev += revincr)
1769 {
1770 fval = speed(dp, sr);
1771 if (sp->contrast_control_on) fval = contrast(dp, amp, ind, fval); else fval *= amp;
1772 fval = mus_fir_filter(dp->flt, fval);
1773 if (dp->reverbing) revin[j] += fval * rev;
1774 buf[j] += fval;
1775 }
1776 }
1777 else
1778 {
1779 if (sp->contrast_control_on)
1780 {
1781 for (j = 0; j < framples; j++, amp += incr, sr += sincr, ind += indincr, rev += revincr)
1782 {
1783 fval = contrast(dp, amp, ind, speed(dp, sr));
1784 if (dp->reverbing) revin[j] += fval * rev;
1785 buf[j] += fval;
1786 }
1787 }
1788 else
1789 {
1790 if (dp->never_sped)
1791 {
1792 for (j = 0; j < framples; j++, amp += incr, rev += revincr)
1793 {
1794 fval = amp * (*(dp->dac_sample))(dp);
1795 revin[j] += fval * rev;
1796 buf[j] += fval;
1797 }
1798 }
1799 else
1800 {
1801 for (j = 0; j < framples; j++, amp += incr, sr += sincr, rev += revincr)
1802 {
1803 fval = amp * speed(dp, sr);
1804 revin[j] += fval * rev;
1805 buf[j] += fval;
1806 }
1807 }
1808 }
1809 }
1810 }
1811 dp->cur_srate = sr;
1812 dp->cur_amp = amp;
1813 dp->cur_rev = rev;
1814 dp->cur_index = ind;
1815 break;
1816 }
1817 if ((dp->end != NO_END_SPECIFIED) && (dp->end != 0))
1818 {
1819 if ((!dp->chn_fd->cb) ||
1820 ((dp->sp->speed_control_direction > 0) &&
1821 ((dp->chn_fd->at_eof) ||
1822 (dp->end <= current_location(dp->chn_fd)))) ||
1823 ((dp->sp->speed_control_direction < 0) &&
1824 (dp->end > current_location(dp->chn_fd))))
1825 dp->end = 0;
1826 }
1827 }
1828 } /* fill-case loop through max_active_slot */
1829
1830 if (global_rev)
1831 for (i = 0; i < framples; i++)
1832 reverb(global_rev, rev_ins, dac_buffers, i);
1833
1834 /* now hooks, stop-function etc */
1835 for (i = 0; i <= max_active_slot; i++)
1836 {
1837 dp = play_list[i];
1838 if (dp)
1839 {
1840 /* check for EOF or specified end point */
1841 if (write_ok == WRITE_TO_DAC) /* not Apply */
1842 {
1843 if (dp->end == 0)
1844 stop_playing(dp, WITH_HOOK, PLAY_COMPLETE);
1845 else
1846 {
1847 if ((dp->chn_fd) &&
1848 (dp->chn_fd->at_eof))
1849 {
1850 if (!(dp->expanding))
1851 stop_playing(dp, WITH_HOOK, PLAY_COMPLETE);
1852 else
1853 {
1854 dp->expand_ring_framples -= framples;
1855 if (dp->expand_ring_framples <= 0)
1856 stop_playing(dp, WITH_HOOK, PLAY_COMPLETE);
1857 }
1858 }
1859 }
1860 }
1861 else /* Apply, always sets the end point explicitly */
1862 {
1863 if (dp->end == 0)
1864 {
1865 stop_playing_all_sounds_without_hook(PLAY_COMPLETE);
1866 play_list_members = 0;
1867 max_active_slot = -1;
1868 }
1869 }
1870 }
1871 } /* stop-case loop through max_active_slot */
1872
1873 if ((global_rev) &&
1874 (snd_dacp) &&
1875 (play_list_members == 0))
1876 {
1877 snd_dacp->reverb_ring_framples -= framples;
1878 if (snd_dacp->reverb_ring_framples <= 0)
1879 free_reverb();
1880 }
1881 }
1882 /* now parcel these buffers out to the available devices */
1883
1884 if (snd_dacp)
1885 {
1886 #if (HAVE_OSS || HAVE_ALSA)
1887 if (write_ok == WRITE_TO_DAC)
1888 {
1889 mus_float_t **dev_bufs;
1890 dev_bufs = dac_buffers;
1891 for (i = 0; i < snd_dacp->devices; i++)
1892 if (dev_fd[i] != -1)
1893 {
1894 mus_file_write_buffer(snd_dacp->out_samp_type,
1895 0, framples - 1,
1896 snd_dacp->chans_per_device[i],
1897 dev_bufs,
1898 (char *)(audio_bytes[i]),
1899 clipping(ss));
1900 dev_bufs += snd_dacp->chans_per_device[i];
1901 }
1902 for (i = 0; i < snd_dacp->devices; i++)
1903 if (dev_fd[i] != -1)
1904 {
1905 int bytes;
1906 bytes = snd_dacp->chans_per_device[i] * framples * mus_bytes_per_sample(snd_dacp->out_samp_type);
1907 mus_audio_write(dev_fd[i], (char *)(audio_bytes[i]), bytes);
1908 }
1909 }
1910 #else
1911 if (write_ok == WRITE_TO_DAC)
1912 {
1913 int bytes;
1914 mus_file_write_buffer(snd_dacp->out_samp_type, 0, framples - 1, snd_dacp->channels, dac_buffers, (char *)(audio_bytes[0]), clipping(ss));
1915 bytes = snd_dacp->channels * framples * mus_bytes_per_sample(snd_dacp->out_samp_type);
1916 mus_audio_write(dev_fd[0], (char *)(audio_bytes[0]), bytes);
1917 }
1918 #endif
1919 }
1920 if (cursor_change) cursor_time = 0;
1921 return(framples);
1922 }
1923
1924
1925 /* -------------------------------- specialize mus_print -------------------------------- */
1926
1927 static mus_print_handler_t *old_dac_printer = NULL;
1928 static char *last_print = NULL;
1929
dac_mus_print(char * msg)1930 static void dac_mus_print(char *msg)
1931 {
1932 if (last_print) free(last_print);
1933 last_print = mus_strdup(msg);
1934 (*old_dac_printer)(msg);
1935 }
1936
1937
set_dac_print(void)1938 static void set_dac_print(void)
1939 {
1940 if (last_print) free(last_print);
1941 last_print = NULL;
1942 if (old_dac_printer != dac_mus_print)
1943 old_dac_printer = mus_print_set_handler(dac_mus_print);
1944 }
1945
1946
unset_dac_print(void)1947 static void unset_dac_print(void)
1948 {
1949 mus_print_set_handler(old_dac_printer);
1950 }
1951
1952
1953 #if WITH_AUDIO
describe_dac(void)1954 static const char *describe_dac(void)
1955 {
1956 /* this is only called in dac_error and only then upon a failed mus_audio_open_output */
1957 int players = 0, i;
1958 dac_info *ptr = NULL;
1959 for (i = 0; i < dac_max_sounds; i++)
1960 if (play_list[i])
1961 {
1962 ptr = play_list[i];
1963 players++;
1964 }
1965 if ((players == 1) &&
1966 (ptr->sp))
1967 return((const char *)(ptr->sp->short_filename));
1968 return("");
1969 }
1970 #endif
1971
1972
dac_error(void)1973 static void dac_error(void)
1974 {
1975 stop_playing_all_sounds_without_hook(PLAY_ERROR);
1976 #if WITH_AUDIO
1977 snd_error("can't play %s: %s",
1978 describe_dac(),
1979 (last_print) ? last_print : "reason not known");
1980 #endif
1981 }
1982
1983
1984 /* -------------------------------- initialize DAC -------------------------------- */
1985
make_dac_buffers(void)1986 static void make_dac_buffers(void)
1987 {
1988 /* make the per-channel buffers and audio output buffers */
1989 int bytes, i;
1990
1991 if ((!dac_buffers) ||
1992 (dac_buffer_chans < snd_dacp->channels) ||
1993 (dac_buffer_size < snd_dacp->framples))
1994 {
1995 if (dac_buffers)
1996 {
1997 for (i = 0; i < dac_buffer_chans; i++) free(dac_buffers[i]);
1998 free(dac_buffers);
1999 }
2000 if (rev_ins)
2001 {
2002 for (i = 0; i < dac_buffer_chans; i++) free(rev_ins[i]);
2003 free(rev_ins);
2004 }
2005 dac_buffers = (mus_float_t **)calloc(snd_dacp->channels, sizeof(mus_float_t *));
2006 rev_ins = (mus_float_t **)calloc(snd_dacp->channels, sizeof(mus_float_t *));
2007 for (i = 0; i < snd_dacp->channels; i++)
2008 {
2009 dac_buffers[i] = (mus_float_t *)calloc(snd_dacp->framples, sizeof(mus_float_t));
2010 rev_ins[i] = (mus_float_t *)calloc(snd_dacp->framples, sizeof(mus_float_t));
2011 }
2012 dac_buffer_chans = snd_dacp->channels;
2013 dac_buffer_size = snd_dacp->framples;
2014 if (r_outs) free(r_outs);
2015 if (r_ins) free(r_ins);
2016 r_outs = (mus_float_t *)calloc(snd_dacp->channels, sizeof(mus_float_t));
2017 r_ins = (mus_float_t *)calloc(snd_dacp->channels, sizeof(mus_float_t));
2018 }
2019
2020 bytes = snd_dacp->channels * dac_buffer_size * mus_bytes_per_sample(snd_dacp->out_samp_type);
2021 if ((audio_bytes_size < bytes) ||
2022 (audio_bytes_devices < snd_dacp->devices))
2023 {
2024 if (audio_bytes)
2025 {
2026 for (i = 0; i < audio_bytes_devices; i++) free(audio_bytes[i]);
2027 free(audio_bytes);
2028 }
2029 audio_bytes = (unsigned char **)calloc(snd_dacp->devices, sizeof(unsigned char *));
2030 for (i = 0; i < snd_dacp->devices; i++)
2031 audio_bytes[i] = (unsigned char *)calloc(bytes, sizeof(unsigned char));
2032 audio_bytes_size = bytes;
2033 audio_bytes_devices = snd_dacp->devices;
2034 }
2035 }
2036
2037
2038 static void stop_audio_output(void);
2039
2040 #if (HAVE_ALSA || HAVE_OSS)
2041
2042
2043 /* Controls behavior of device selection logic below. No amount of logic
2044 * can make everybody happy all the time. The [i]logic below cannot always
2045 * produce the desired result but deleting it altogether will break the
2046 * systems that currently rely on it. Not wise without an external api
2047 * in place designed to select whatever the user _really_ wants. Till
2048 * then set this to "1" to always send to the first device. */
2049
2050 static int feed_first_device = 0;
2051
2052 #define ALSA_MAX_DEVICES 64
2053 static int alsa_devices[ALSA_MAX_DEVICES];
2054 static int alsa_available_chans[ALSA_MAX_DEVICES];
2055 static int alsa_max_chans[ALSA_MAX_DEVICES];
2056 static int alsa_min_chans[ALSA_MAX_DEVICES];
2057
2058 static int alsa_max_chans_value = 0;
2059 static int alsa_max_chans_dev = 0;
2060 static bool audio_devices_scanned = false;
2061 static int alsa_devices_available = 0;
2062
2063 void mus_audio_alsa_channel_info(int dev, int *info);
2064 void mus_audio_alsa_device_list(int sys, int size, int *val);
2065 int mus_audio_alsa_device_direction(int dev);
2066
scan_audio_devices(void)2067 static void scan_audio_devices(void)
2068 {
2069 int cards, card, devs, dev, d;
2070 int index = 0;
2071 int direction;
2072 int val[ALSA_MAX_DEVICES];
2073 if (!audio_devices_scanned)
2074 {
2075 audio_devices_scanned = true;
2076 /* At this time
2077 * we always select the widest device if the requested channels fit into it.
2078 * Otherwise we try to combine devices, if all fails we modify snd settings
2079 * so that channel folding takes place. This is inefficient but works for now.
2080 */
2081 cards = 1;
2082 index = 0;
2083 /* scan all cards and build a list of available output devices */
2084 for (card = 0; card < cards; card++)
2085 {
2086 mus_audio_alsa_device_list(MUS_AUDIO_PACK_SYSTEM(card), ALSA_MAX_DEVICES, val);
2087 devs = val[0];
2088 /* scan all devices in the card */
2089 for (d = 0; d < devs; d++)
2090 {
2091 dev = val[d + 1];
2092 direction = mus_audio_alsa_device_direction(MUS_AUDIO_PACK_SYSTEM(card) | dev);
2093 if (direction == 0)
2094 {
2095 /* remember output device */
2096 alsa_devices[index++] = MUS_AUDIO_PACK_SYSTEM(card) | dev;
2097 if (index >= ALSA_MAX_DEVICES) goto NO_MORE_DEVICES;
2098 }
2099 }
2100 }
2101 NO_MORE_DEVICES:
2102 /* get channel availability for all devices */
2103 for (d = 0; d < index; d++)
2104 {
2105 int chan_info[4];
2106 alsa_available_chans[d] = 0;
2107 alsa_min_chans[d] = 0;
2108 alsa_max_chans[d] = 0;
2109 mus_audio_alsa_channel_info(alsa_devices[d], chan_info);
2110 alsa_available_chans[d] = chan_info[0];
2111 alsa_min_chans[d] = chan_info[1];
2112 alsa_max_chans[d] = chan_info[2];
2113 if (alsa_max_chans[d] > alsa_max_chans_value)
2114 {
2115 /* remember widest device */
2116 alsa_max_chans_value = alsa_max_chans[d];
2117 alsa_max_chans_dev = d;
2118 }
2119 }
2120 }
2121 alsa_devices_available = index;
2122 }
2123
2124 int mus_audio_alsa_samples_per_channel(int dev);
2125
start_audio_output_1(void)2126 static bool start_audio_output_1(void)
2127 {
2128 int i;
2129
2130 /* -------------------- ALSA not OSS -------------------- */
2131 if (mus_audio_api() == MUS_ALSA_API)
2132 {
2133 static int out_dev[ALSA_MAX_DEVICES];
2134 int d, alloc_chans, alloc_devs;
2135 scan_audio_devices();
2136 /* allocate devices for playback */
2137 alloc_chans = 0;
2138 alloc_devs = 0;
2139 for (d = 0; d < ALSA_MAX_DEVICES; d++) out_dev[d] = -1;
2140 for (d = 0; d < MAX_DEVICES; d++) dev_fd[d] = -1;
2141 if (feed_first_device == 0)
2142 {
2143 /* see if widest device can accommodate all channels */
2144 if (alsa_max_chans_value >= snd_dacp->channels)
2145 {
2146 out_dev[alloc_devs++] = alsa_max_chans_dev;
2147 alloc_chans += alsa_max_chans_value;
2148 }
2149 if (alloc_devs == 0)
2150 {
2151 /* try to use several devices */
2152 int prev_samp_type = -1;
2153 for (d = 0; d < alsa_devices_available; d++)
2154 {
2155 int this_samp_type;
2156 this_samp_type = mus_audio_compatible_sample_type(alsa_devices[d]);
2157 if (prev_samp_type == -1)
2158 {
2159 prev_samp_type = this_samp_type;
2160 }
2161 /* samp_type for all selected devices should match */
2162 if (this_samp_type == prev_samp_type)
2163 {
2164 out_dev[alloc_devs++] = d;
2165 alloc_chans += alsa_available_chans[d];
2166 if (alloc_devs >= ALSA_MAX_DEVICES)
2167 break;
2168 }
2169 }
2170 if ((alloc_devs != 0) && (alloc_chans < snd_dacp->channels))
2171 {
2172 /* not enough available channels, give up */
2173 for (d = 0; d < ALSA_MAX_DEVICES; d++) out_dev[d] = -1;
2174 alloc_devs = 0;
2175 alloc_chans = 0;
2176 }
2177 if (alloc_devs == 0)
2178 {
2179 /* fold all channels into the first device */
2180 out_dev[alloc_devs++] = 0;
2181 alloc_chans += alsa_available_chans[0];
2182 }
2183 }
2184 }
2185 else
2186 {
2187 /* first device on first card is the one */
2188 out_dev[alloc_devs++] = 0;
2189 alloc_chans += alsa_available_chans[0];
2190 }
2191 snd_dacp->out_samp_type = mus_audio_compatible_sample_type(alsa_devices[out_dev[0]]);
2192 if (alloc_devs < 2)
2193 {
2194 /* see if we have a minimum sized frample to fill
2195 * FIXME: could this happen in more than one device? */
2196 int c;
2197 c = alsa_min_chans[out_dev[0]];
2198 if (c > snd_dacp->channels)
2199 {
2200 snd_dacp->channels = c;
2201 }
2202 }
2203 /* see if we have to fold channels */
2204 if (alloc_chans < snd_dacp->channels)
2205 {
2206 if (dac_combines_channels(ss))
2207 snd_warning("folding %d chans into %d ",
2208 snd_dacp->channels, alloc_chans);
2209 snd_dacp->channels = alloc_chans;
2210 }
2211
2212 {
2213 int samples_per_channel;
2214 /* read the number of samples per channel the device wants buffered */
2215 samples_per_channel = mus_audio_alsa_samples_per_channel(alsa_devices[out_dev[0]]);
2216 snd_dacp->framples = samples_per_channel;
2217 /* set_dac_size(snd_dacp->framples * mus_bytes_per_sample(snd_dacp->out_samp_type)); */
2218 set_dac_size(samples_per_channel); /* bil 24-Mar-13 */
2219 }
2220 /* open all allocated devices */
2221 for (d = 0; d < alloc_devs; d++)
2222 {
2223 int channels;
2224 channels = alsa_available_chans[out_dev[d]];
2225 if (alloc_chans <= alsa_available_chans[out_dev[d]])
2226 {
2227 if (snd_dacp->channels < alsa_min_chans[out_dev[d]])
2228 {
2229 channels = alsa_min_chans[out_dev[d]];
2230 }
2231 else
2232 {
2233 channels = snd_dacp->channels;
2234 }
2235 }
2236 /* FIXME: assumes devices are same size... */
2237 set_dac_print();
2238 dev_fd[d] = mus_audio_open_output(alsa_devices[out_dev[d]],
2239 snd_dacp->srate,
2240 channels,
2241 snd_dacp->out_samp_type,
2242 snd_dacp->framples * channels * mus_bytes_per_sample(snd_dacp->out_samp_type));
2243 unset_dac_print();
2244
2245 if (dev_fd[d] == -1)
2246 {
2247 /* could not open a device, close all others and quit playback */
2248 int i;
2249 for (i = 0; i < d; i++)
2250 {
2251 mus_audio_close(alsa_devices[out_dev[i]]);
2252 }
2253 dac_error();
2254 dac_running = false;
2255 if (global_rev) free_reverb();
2256 max_active_slot = -1;
2257 return(false);
2258 }
2259 }
2260 snd_dacp->devices = (alloc_devs > 1000000) ? 1000000 : alloc_devs; /* placate damned gcc */
2261 /* for now assume all are same number of chans */
2262 snd_dacp->chans_per_device = (int *)calloc(snd_dacp->devices, sizeof(int));
2263 for (i = 0; i < snd_dacp->devices; i++)
2264 snd_dacp->chans_per_device[i] = snd_dacp->channels / snd_dacp->devices;
2265 make_dac_buffers();
2266 }
2267 else
2268 {
2269
2270 /* -------------------- OSS not ALSA -------------------- */
2271 /* api == MUS_OSS_API -- MUS_JACK_API should not intrude here because we're in HAVE_ALSA || HAVE_OSS */
2272 int oss_available_chans = 2;
2273
2274 if (snd_dacp->channels > 2)
2275 oss_available_chans = mus_audio_device_channels(MUS_AUDIO_DEFAULT);
2276 for (i = 0; i < MAX_DEVICES; i++) dev_fd[i] = -1;
2277 /* see if we can play 16 bit output */
2278 snd_dacp->out_samp_type = mus_audio_compatible_sample_type(MUS_AUDIO_DEFAULT);
2279
2280 /* removed PPC stuff here 30-Apr-12 */
2281
2282 if ((oss_available_chans < snd_dacp->channels) &&
2283 (oss_available_chans > 0))
2284 {
2285 if (dac_combines_channels(ss))
2286 snd_warning("folding %d chans into %d ",
2287 snd_dacp->channels, oss_available_chans);
2288 snd_dacp->channels = oss_available_chans;
2289 }
2290 set_dac_print();
2291 if (dev_fd[0] == MUS_ERROR)
2292 dev_fd[0] = mus_audio_open_output(MUS_AUDIO_DEFAULT,
2293 snd_dacp->srate, snd_dacp->channels,
2294 snd_dacp->out_samp_type,
2295 dac_size(ss));
2296 unset_dac_print();
2297 if (dev_fd[0] == MUS_ERROR)
2298 {
2299 dac_error();
2300 stop_audio_output();
2301 return(false);
2302 }
2303 snd_dacp->devices = (dev_fd[1] != -1) ? 2 : 1;
2304 snd_dacp->chans_per_device = (int *)calloc(snd_dacp->devices, sizeof(int));
2305 for (i = 0; i < snd_dacp->devices; i++)
2306 snd_dacp->chans_per_device[i] = snd_dacp->channels / snd_dacp->devices;
2307 make_dac_buffers();
2308 }
2309 return(true);
2310 }
2311 #else /* not ALSA or OSS */
2312
start_audio_output_1(void)2313 static bool start_audio_output_1(void)
2314 {
2315 int i;
2316 int available_chans = 2;
2317
2318 if (snd_dacp->channels > 2)
2319 available_chans = mus_audio_device_channels(MUS_AUDIO_DEFAULT);
2320
2321 if (available_chans <= 0)
2322 {
2323 snd_warning("no available channels??");
2324 return(false);
2325 }
2326 if (available_chans < snd_dacp->channels)
2327 {
2328 if (dac_combines_channels(ss))
2329 snd_warning("folding %d chans into %d ",
2330 snd_dacp->channels,
2331 available_chans);
2332 snd_dacp->channels = available_chans;
2333 }
2334
2335 for (i = 0; i < MAX_DEVICES; i++) dev_fd[i] = -1;
2336 snd_dacp->out_samp_type = mus_audio_device_sample_type(MUS_AUDIO_DEFAULT);
2337
2338 set_dac_print();
2339 if (dev_fd[0] == MUS_ERROR)
2340 dev_fd[0] = mus_audio_open_output(MUS_AUDIO_DEFAULT,
2341 snd_dacp->srate,
2342 snd_dacp->channels,
2343 snd_dacp->out_samp_type,
2344 dac_size(ss));
2345 unset_dac_print();
2346 if (dev_fd[0] == MUS_ERROR)
2347 {
2348 dac_error();
2349 stop_audio_output();
2350 return(false);
2351 }
2352 snd_dacp->devices = 1;
2353 snd_dacp->chans_per_device = (int *)calloc(snd_dacp->devices, sizeof(int));
2354 for (i = 0; i < snd_dacp->devices; i++)
2355 snd_dacp->chans_per_device[i] = available_chans / snd_dacp->devices;
2356 make_dac_buffers();
2357 return(true);
2358 }
2359 #endif
2360
2361
start_audio_output(void)2362 static bool start_audio_output(void)
2363 {
2364 /* at this point the desired output srate and chans are set in dacp (via start_dac) */
2365 cursor_time = 0;
2366 if (start_audio_output_1()) /* number of channels may be less than requested initially */
2367 {
2368 int i;
2369 for (i = 0; i <= max_active_slot; i++)
2370 {
2371 dac_info *dp;
2372 dp = play_list[i];
2373 if (dp)
2374 {
2375 /* deferred reverb allocation since start_audio_output_1 may force more chans open */
2376 if ((dp->reverbing) &&
2377 (dp->sp) &&
2378 (!global_rev))
2379 make_reverb(dp->sp, snd_dacp->channels);
2380
2381 if (dp->audio_chan >= snd_dacp->channels)
2382 {
2383 if (dac_combines_channels(ss))
2384 dp->audio_chan %= snd_dacp->channels;
2385 else stop_playing(dp, WITHOUT_HOOK, PLAY_NO_CHANNEL);
2386 }
2387 }
2388 }
2389 dac_running = true;
2390 fill_dac_buffers(WRITE_TO_DAC);
2391 if (!snd_dacp) return(false);
2392 return(true);
2393 }
2394 return(false);
2395 }
2396
2397
stop_audio_output(void)2398 static void stop_audio_output(void)
2399 {
2400 int i;
2401 for (i = 0; i < MAX_DEVICES; i++)
2402 if (dev_fd[i] != -1)
2403 {
2404 mus_audio_close(dev_fd[i]);
2405 dev_fd[i] = -1;
2406 }
2407 dac_running = false;
2408 dac_pausing = false;
2409 if (global_rev) free_reverb();
2410 max_active_slot = -1;
2411 }
2412
2413
dac_in_background(any_pointer_t ptr)2414 static idle_func_t dac_in_background(any_pointer_t ptr)
2415 {
2416 /* slice 0: try to open audio output devices and get ready to send samples
2417 * 1: loop sending data until the play_list is empty or some error (C-g) happens
2418 * 2: try to close all active outputs and remove background procedure
2419 */
2420 if (!snd_dacp) return(BACKGROUND_QUIT);
2421 switch (snd_dacp->slice)
2422 {
2423 case 0:
2424 if (start_audio_output())
2425 {
2426 if (!snd_dacp) return(BACKGROUND_QUIT);
2427 snd_dacp->slice = 1;
2428 return(BACKGROUND_CONTINUE);
2429 }
2430 else
2431 {
2432 free_dac_state();
2433 return(BACKGROUND_QUIT);
2434 }
2435 break;
2436
2437 case 1:
2438 fill_dac_buffers(WRITE_TO_DAC);
2439 if (!snd_dacp) return(BACKGROUND_QUIT); /* dac-hook called stop-playing or something equally perverse */
2440 if ((!global_rev) && (play_list_members == 0)) snd_dacp->slice = 2;
2441 return(BACKGROUND_CONTINUE);
2442 break;
2443
2444 case 2:
2445 stop_audio_output();
2446 free_dac_state();
2447 return(BACKGROUND_QUIT);
2448 break;
2449 }
2450 return(BACKGROUND_QUIT);
2451 }
2452
2453
2454
2455 /* ---------------- support for Apply button (snd-apply.c) ---------------- */
2456
initialize_apply(snd_info * sp,int chans,mus_long_t beg,mus_long_t dur)2457 void initialize_apply(snd_info *sp, int chans, mus_long_t beg, mus_long_t dur)
2458 {
2459 int curchan = 0;
2460
2461 stop_playing_all_sounds_without_hook(PLAY_APPLY);
2462
2463 if (snd_dacp) /* may not have been able to complete despite slice=2 in stop all */
2464 {
2465 snd_dacp->slice = 2;
2466 dac_in_background(NULL); /* so try to force completion */
2467 }
2468
2469 if (chans <= 0) return;
2470 max_active_slot = -1;
2471 play_list_members = 0;
2472 dac_running = true; /* this keeps start_dac from actually starting the dac */
2473 if (snd_dacp) free_dac_state();
2474
2475 snd_dacp = (dac_state *)calloc(1, sizeof(dac_state));
2476 snd_dacp->slice = 0;
2477 snd_dacp->srate = snd_srate(sp);
2478 snd_dacp->out_samp_type = MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE;
2479 if (snd_dacp->srate <= 0) snd_dacp->srate = 44100;
2480 snd_dacp->channels = chans;
2481 snd_dacp->framples = 8192;
2482 snd_dacp->devices = 1;
2483 snd_dacp->chans_per_device = (int *)calloc(1, sizeof(int));
2484 snd_dacp->chans_per_device[0] = chans;
2485 snd_dacp->reverb_ring_framples = (mus_long_t)(snd_dacp->srate * sp->reverb_control_decay);
2486 make_dac_buffers();
2487
2488 switch (ss->apply_choice)
2489 {
2490 case APPLY_TO_SOUND:
2491 play_sound(sp, beg, beg + dur);
2492 break;
2493
2494 case APPLY_TO_SELECTION:
2495 play_selection(IN_BACKGROUND);
2496 break;
2497
2498 case APPLY_TO_CHANNEL:
2499 if (sp->selected_channel != NO_SELECTION)
2500 curchan = sp->selected_channel;
2501 play_channel(sp->chans[curchan], beg, beg + dur);
2502 break;
2503 }
2504 }
2505
2506
finalize_apply(snd_info * sp)2507 void finalize_apply(snd_info *sp)
2508 {
2509 /* if no reverb, these need to be cleaned up */
2510 stop_playing_all_sounds_without_hook(PLAY_APPLY);
2511 max_active_slot = -1;
2512 play_list_members = 0;
2513 sp->playing = 0;
2514 dac_running = false;
2515 if (snd_dacp) free_dac_state();
2516 if (global_rev) free_reverb();
2517 }
2518
2519
run_apply(int ofd)2520 int run_apply(int ofd)
2521 {
2522 int len, chans;
2523 if (!(snd_dacp)) return(-1);
2524 chans = snd_dacp->channels; /* snd_dacp might be freed by fill_dac_buffers */
2525 len = fill_dac_buffers(WRITE_TO_FILE);
2526 mus_file_write(ofd, 0, len - 1, chans, dac_buffers);
2527 return(len);
2528 }
2529
2530
2531
2532 /* -------- players -------- */
2533
2534 static snd_info **players = NULL;
2535 static int *player_chans = NULL;
2536 static int players_size = 0;
2537
new_player_index(void)2538 static int new_player_index(void)
2539 {
2540 int i, old_size;
2541
2542 if (players_size == 0)
2543 {
2544 players_size = 8;
2545 players = (snd_info **)calloc(players_size, sizeof(snd_info *));
2546 player_chans = (int *)calloc(players_size, sizeof(int));
2547 return(-1);
2548 }
2549
2550 for (i = 1; i < players_size; i++)
2551 if (!players[i])
2552 return(-i);
2553
2554 old_size = players_size;
2555 players_size += 8;
2556 players = (snd_info **)realloc(players, players_size * sizeof(snd_info *));
2557 player_chans = (int *)realloc(player_chans, players_size * sizeof(int));
2558 for (i = old_size; i < players_size; i++)
2559 {
2560 players[i] = NULL;
2561 player_chans[i] = 0;
2562 }
2563 return(-old_size);
2564 }
2565
2566 #define PLAYER(Sp) -(Sp->index)
2567
make_player(snd_info * sp,chan_info * cp)2568 static int make_player(snd_info *sp, chan_info *cp)
2569 {
2570 /* store sp so we can access it via find_sound (get_sp) later */
2571 players[PLAYER(sp)] = sp;
2572 player_chans[PLAYER(sp)] = cp->chan;
2573 return(-sp->index);
2574 }
2575
free_player_sound(snd_info * sp)2576 static void free_player_sound(snd_info *sp)
2577 {
2578 if (players)
2579 {
2580 players[PLAYER(sp)] = NULL;
2581 player_chans[PLAYER(sp)] = 0;
2582 }
2583 free(sp->filename);
2584 sp->filename = NULL;
2585 free(sp->chans);
2586 sp->chans = NULL;
2587 if (sp->filter_control_envelope) sp->filter_control_envelope = free_env(sp->filter_control_envelope);
2588 sp->inuse = SOUND_IDLE;
2589 free(sp);
2590 }
2591
2592
clear_players(void)2593 void clear_players(void)
2594 {
2595 /* called only in free_snd_info, snd-data.c -- make sure currently closing sound is not playing (via a user-created player) */
2596 int i;
2597 for (i = 0; i < players_size; i++)
2598 {
2599 uint32_t j;
2600 snd_info *sp;
2601 sp = players[i];
2602 if (sp)
2603 for (j = 0; j < sp->nchans; j++)
2604 if ((!sp->chans[j]) ||
2605 (sp->chans[j]->active < CHANNEL_HAS_EDIT_LIST) ||
2606 (!sp->chans[j]->sound))
2607 {
2608 int k;
2609 for (k = 0; k <= max_active_slot; k++)
2610 {
2611 dac_info *dp;
2612 dp = play_list[k];
2613 if ((dp) && (sp == dp->sp))
2614 {
2615 play_list[k] = NULL;
2616 play_list_members--;
2617 free_dac_info(dp, PLAY_CLOSE); /* calls stop-function, if any. used in snd-data.c in free_snd_info */
2618 }
2619 }
2620 if (is_player_sound(sp)) free_player_sound(sp);
2621 break;
2622 }
2623 }
2624 }
2625
2626
2627 /* ---------------------------------------- player objects ---------------------------------------- */
2628
2629 typedef struct {
2630 int n;
2631 } xen_player;
2632
2633
2634 #define Xen_to_xen_player(arg) ((xen_player *)Xen_object_ref(arg))
2635
xen_player_to_int(Xen n)2636 static int xen_player_to_int(Xen n)
2637 {
2638 xen_player *mx;
2639 mx = Xen_to_xen_player(n);
2640 return(mx->n);
2641 }
2642
2643 #define Xen_player_to_C_int(Player) xen_player_to_int(Player)
2644
2645
get_player_sound(Xen obj)2646 snd_info *get_player_sound(Xen obj)
2647 {
2648 return(players[xen_player_to_int(obj)]);
2649 }
2650
2651
2652 static Xen_object_type_t xen_player_tag;
2653
xen_is_player(Xen obj)2654 bool xen_is_player(Xen obj)
2655 {
2656 return(Xen_c_object_is_type(obj, xen_player_tag));
2657 }
2658
2659
2660 #if (!HAVE_SCHEME)
xen_player_free(xen_player * v)2661 static void xen_player_free(xen_player *v) {if (v) free(v);}
2662
Xen_wrap_free(xen_player,free_xen_player,xen_player_free)2663 Xen_wrap_free(xen_player, free_xen_player, xen_player_free)
2664 #else
2665 static s7_pointer s7_xen_player_free(s7_scheme *sc, s7_pointer obj)
2666 {
2667 xen_player *v;
2668 v = (xen_player *)s7_c_object_value(obj);
2669 if (v) free(v); /* can it be NULL? */
2670 return(NULL);
2671 }
2672 #endif
2673
2674 static char *xen_player_to_string(xen_player *v)
2675 {
2676 #define PLAYER_PRINT_BUFFER_SIZE 64
2677 char *buf;
2678 if (!v) return(NULL);
2679 buf = (char *)calloc(PLAYER_PRINT_BUFFER_SIZE, sizeof(char));
2680 snprintf(buf, PLAYER_PRINT_BUFFER_SIZE, "#<player %d>", v->n);
2681 return(buf);
2682 }
2683
2684
2685 #if HAVE_FORTH || HAVE_RUBY
Xen_wrap_print(xen_player,print_xen_player,xen_player_to_string)2686 Xen_wrap_print(xen_player, print_xen_player, xen_player_to_string)
2687
2688 static Xen g_xen_player_to_string(Xen obj)
2689 {
2690 char *vstr;
2691 Xen result;
2692 #define S_xen_player_to_string "player->string"
2693 Xen_check_type(xen_is_player(obj), obj, 1, S_xen_player_to_string, "a player");
2694 vstr = xen_player_to_string(Xen_to_xen_player(obj));
2695 result = C_string_to_Xen_string(vstr);
2696 free(vstr);
2697 return(result);
2698 }
2699 #else
2700 #if HAVE_SCHEME
g_xen_player_to_string(s7_scheme * sc,s7_pointer args)2701 static s7_pointer g_xen_player_to_string(s7_scheme *sc, s7_pointer args)
2702 {
2703 char *vstr;
2704 Xen result;
2705 vstr = xen_player_to_string(Xen_to_xen_player(s7_car(args)));
2706 result = C_string_to_Xen_string(vstr);
2707 free(vstr);
2708 return(result);
2709 }
2710 #endif
2711 #endif
2712
2713
2714 #if (!HAVE_SCHEME)
xen_player_equalp(xen_player * v1,xen_player * v2)2715 static bool xen_player_equalp(xen_player *v1, xen_player *v2)
2716 {
2717 return((v1 == v2) ||
2718 (v1->n == v2->n));
2719 }
2720
equalp_xen_player(Xen obj1,Xen obj2)2721 static Xen equalp_xen_player(Xen obj1, Xen obj2)
2722 {
2723 if ((!(xen_is_player(obj1))) || (!(xen_is_player(obj2)))) return(Xen_false);
2724 return(C_bool_to_Xen_boolean(xen_player_equalp(Xen_to_xen_player(obj1), Xen_to_xen_player(obj2))));
2725 }
2726 #endif
2727
2728
xen_player_make(int n)2729 static xen_player *xen_player_make(int n)
2730 {
2731 xen_player *new_v;
2732 new_v = (xen_player *)malloc(sizeof(xen_player));
2733 new_v->n = n;
2734 return(new_v);
2735 }
2736
2737
new_xen_player(int n)2738 static Xen new_xen_player(int n)
2739 {
2740 xen_player *mx;
2741 if (n < 0)
2742 return(Xen_false);
2743
2744 mx = xen_player_make(n);
2745 return(Xen_make_object(xen_player_tag, mx, 0, free_xen_player));
2746 }
2747
2748 #define C_int_to_Xen_player(val) new_xen_player(val)
2749
2750
2751 #if HAVE_SCHEME
s7_xen_player_is_equal(s7_scheme * sc,s7_pointer args)2752 static s7_pointer s7_xen_player_is_equal(s7_scheme *sc, s7_pointer args)
2753 {
2754 s7_pointer p1, p2;
2755 p1 = s7_car(args);
2756 p2 = s7_cadr(args);
2757 if (p1 == p2) return(s7_t(sc));
2758 if (s7_c_object_type(p2) == xen_player_tag)
2759 return(s7_make_boolean(sc, (((xen_player *)s7_c_object_value(p1))->n == ((xen_player *)s7_c_object_value(p2))->n)));
2760 return(s7_f(sc));
2761 }
2762
s7_xen_player_length(s7_scheme * sc,s7_pointer args)2763 static s7_pointer s7_xen_player_length(s7_scheme *sc, s7_pointer args)
2764 {
2765 chan_info *cp;
2766 int index;
2767 index = Xen_player_to_C_int(s7_car(args));
2768 cp = players[index]->chans[player_chans[index]];
2769 return(C_llong_to_Xen_llong(current_samples(cp)));
2770 }
2771 #endif
2772
2773
init_xen_player(void)2774 static void init_xen_player(void)
2775 {
2776 #if HAVE_SCHEME
2777 xen_player_tag = s7_make_c_type(s7, "<player>");
2778 s7_c_type_set_gc_free(s7, xen_player_tag, s7_xen_player_free);
2779 s7_c_type_set_is_equal(s7, xen_player_tag, s7_xen_player_is_equal);
2780 s7_c_type_set_length(s7, xen_player_tag, s7_xen_player_length);
2781 s7_c_type_set_to_string(s7, xen_player_tag, g_xen_player_to_string);
2782 #else
2783 #if HAVE_RUBY
2784 xen_player_tag = Xen_make_object_type("XenPlayer", sizeof(xen_player));
2785 #else
2786 xen_player_tag = Xen_make_object_type("Player", sizeof(xen_player));
2787 #endif
2788 #endif
2789
2790 #if HAVE_FORTH
2791 fth_set_object_inspect(xen_player_tag, print_xen_player);
2792 fth_set_object_dump(xen_player_tag, g_xen_player_to_string);
2793 fth_set_object_equal(xen_player_tag, equalp_xen_player);
2794 fth_set_object_free(xen_player_tag, free_xen_player);
2795 #endif
2796
2797 #if HAVE_RUBY
2798 rb_define_method(xen_player_tag, "to_s", Xen_procedure_cast print_xen_player, 0);
2799 rb_define_method(xen_player_tag, "eql?", Xen_procedure_cast equalp_xen_player, 1);
2800 rb_define_method(xen_player_tag, "==", Xen_procedure_cast equalp_xen_player, 1);
2801 rb_define_method(xen_player_tag, "to_str", Xen_procedure_cast g_xen_player_to_string, 0);
2802 #endif
2803 }
2804
2805 /* -------------------------------------------------------------------------------- */
2806
play_file(const char * play_name,mus_long_t start,mus_long_t end,int in_channel,int out_channel,play_process_t background,Xen stop_func)2807 static Xen play_file(const char *play_name, mus_long_t start, mus_long_t end, int in_channel, int out_channel, play_process_t background, Xen stop_func)
2808 {
2809 snd_info *sp;
2810
2811 if (!(mus_file_probe(play_name)))
2812 return(snd_no_such_file_error(S_play, C_string_to_Xen_string(play_name)));
2813
2814 if (!(mus_is_header_type(mus_sound_header_type(play_name))))
2815 Xen_error(BAD_HEADER,
2816 Xen_list_3(C_string_to_Xen_string(S_play ": ~S has unknown header: ~A"),
2817 C_string_to_Xen_string(play_name),
2818 C_string_to_Xen_string(mus_header_type_name(mus_header_type()))));
2819
2820 if (!(mus_is_sample_type(mus_sound_sample_type(play_name))))
2821 Xen_error(Xen_make_error_type("bad-sample-type"),
2822 Xen_list_3(C_string_to_Xen_string(S_play ": ~S has unknown sample type: ~A"),
2823 C_string_to_Xen_string(play_name),
2824 C_string_to_Xen_string(mus_header_original_sample_type_name(mus_sound_original_sample_type(play_name), mus_sound_header_type(play_name)))));
2825 sp = make_sound_readable(play_name, false);
2826 sp->short_filename = filename_without_directory(play_name);
2827 sp->filename = NULL;
2828 sp->delete_me = (void *)1;
2829 if (in_channel != -1)
2830 play_channel_1(sp->chans[in_channel], start, end, background, 0, stop_func, (out_channel < 0) ? 0 : out_channel);
2831 else play_sound_1(sp, start, end, background, Xen_integer_zero, stop_func, S_play, -1);
2832
2833 return(Xen_false);
2834 }
2835
2836 #if (!HAVE_SCHEME)
2837 static Xen kw_start, kw_end, kw_channel, kw_wait, kw_edit_position, kw_stop, kw_out_channel, kw_with_sync, kw_srate, kw_channels;
2838
init_play_keywords(void)2839 static void init_play_keywords(void)
2840 {
2841 kw_start = Xen_make_keyword("start");
2842 kw_end = Xen_make_keyword("end");
2843 kw_wait = Xen_make_keyword("wait");
2844 kw_channel = Xen_make_keyword("channel");
2845 kw_out_channel = Xen_make_keyword("out-channel");
2846 kw_edit_position = Xen_make_keyword("edit-position");
2847 kw_stop = Xen_make_keyword("stop");
2848 kw_with_sync = Xen_make_keyword("with-sync");
2849 kw_srate = Xen_make_keyword("srate");
2850 kw_channels = Xen_make_keyword("channels");
2851 }
2852 #endif
2853
2854 #if HAVE_SCHEME
2855 #define play_example "(play \"oboe.snd\")"
2856 #endif
2857 #if HAVE_RUBY
2858 #define play_example "play(\"oboe.snd\")"
2859 #endif
2860 #if HAVE_FORTH
2861 #define play_example "\"oboe.snd\" play"
2862 #endif
2863
2864 #define H_play "(" S_play " object start end channel edit-position out-channel with-sync wait stop srate channels): \
2865 play the object from start to end. If channel is not given, play all channels. If with-sync, play all objects sync'd \
2866 to the current object. If wait, wait for the play process to finish before going on. If out-channel, send the samples \
2867 to that DAC channel. If edit-position, play that member of the edit list, otherwise play the current state of the object. \
2868 If stop, call that function when the play process finishes. \
2869 If object is a string, it is assumed to be a file name: \n " play_example "\n."
2870
2871 #if HAVE_SCHEME
g_play(s7_scheme * sc,s7_pointer args)2872 static s7_pointer g_play(s7_scheme *sc, s7_pointer args)
2873 {
2874 s7_pointer object, p, fp;
2875 mus_long_t start, end;
2876 int channel, out_channel, srate, channels, edpos_argpos = 4, channel_argpos = 3;
2877 bool with_sync;
2878 #if (!USE_NO_GUI)
2879 bool wait;
2880 #endif
2881 s7_pointer stop_func, edit_position, channel_arg;
2882 play_process_t background;
2883 snd_info *sp;
2884
2885 object = s7_car(args);
2886 args = s7_cdr(args);
2887
2888 fp = s7_car(args);
2889 if (fp == Xen_false)
2890 start = 0;
2891 else
2892 {
2893 if (!s7_is_integer(fp))
2894 return(s7_wrong_type_arg_error(sc, S_play, 1, fp, "an integer (start)"));
2895 start = s7_integer(fp);
2896 if (start < 0)
2897 Xen_out_of_range_error(S_play, 1, fp, "start is negative?");
2898 }
2899
2900 fp = s7_cadr(args);
2901 if (fp == Xen_false)
2902 end = NO_END_SPECIFIED;
2903 else
2904 {
2905 if (!s7_is_integer(fp))
2906 return(s7_wrong_type_arg_error(sc, S_play, 2, fp, "an integer (end)"));
2907 end = s7_integer(fp);
2908 if (end < -1)
2909 Xen_out_of_range_error(S_play, 2, fp, "end is negative?");
2910 }
2911
2912 p = s7_cddr(args);
2913 fp = s7_car(p);
2914 channel_arg = fp;
2915 if (fp == Xen_false)
2916 channel = -1;
2917 else
2918 {
2919 if (!s7_is_integer(fp))
2920 return(s7_wrong_type_arg_error(sc, S_play, 3, fp, "an integer (channel)"));
2921 channel = s7_integer(fp);
2922 }
2923
2924 edit_position = s7_cadr(p);
2925
2926 p = s7_cddr(p);
2927 fp = s7_car(p);
2928 if (fp == Xen_false)
2929 out_channel = -1;
2930 else
2931 {
2932 if (!s7_is_integer(fp))
2933 return(s7_wrong_type_arg_error(sc, S_play, 5, fp, "an integer (out channel)"));
2934 out_channel = s7_integer(fp);
2935 }
2936
2937 fp = s7_cadr(p);
2938 with_sync = (fp != Xen_false);
2939
2940 p = s7_cddr(p);
2941 #if (!USE_NO_GUI)
2942 fp = s7_car(p);
2943 wait = (fp != Xen_false);
2944 #endif
2945
2946 stop_func = s7_cadr(p);
2947 if ((stop_func != Xen_false) &&
2948 (!s7_is_procedure(stop_func)))
2949 return(s7_wrong_type_arg_error(sc, S_play, 8, stop_func, "a procedure (stop)"));
2950 if ((s7_is_procedure(stop_func)) &&
2951 (!s7_is_aritable(sc, stop_func, 1)))
2952 Xen_bad_arity_error(S_play, 8, fp, "stop function should take 1 argument");
2953
2954 p = s7_cddr(p);
2955 fp = s7_car(p);
2956 if (fp == Xen_false)
2957 srate = 44100;
2958 else
2959 {
2960 if (!s7_is_integer(fp))
2961 return(s7_wrong_type_arg_error(sc, S_play, 9, fp, "an integer (srate)"));
2962 srate = s7_integer(fp);
2963 if (srate <= 0)
2964 Xen_out_of_range_error(S_play, 9, fp, "srate <= 0?");
2965 }
2966
2967 fp = s7_cadr(p);
2968 if (fp == Xen_false)
2969 channels = 2;
2970 else
2971 {
2972 if (!s7_is_integer(fp))
2973 return(s7_wrong_type_arg_error(sc, S_play, 10, fp, "an integer (channels)"));
2974 channels = s7_integer(fp);
2975 if (channels <= 0)
2976 Xen_out_of_range_error(S_play, 10, fp, "channels <= 0?");
2977 }
2978
2979 #else
2980 static Xen g_play(Xen arglist)
2981 {
2982 Xen object = Xen_undefined;
2983 mus_long_t start = 0, end = NO_END_SPECIFIED;
2984 int channel = -1, out_channel = -1, srate = 44100, channels = 2, edpos_argpos = 0, channel_argpos = 0;
2985 bool with_sync = false, wait = false;
2986 Xen stop_func = Xen_false, edit_position = Xen_false, channel_arg = Xen_false;
2987 play_process_t background;
2988 snd_info *sp;
2989
2990 if (!Xen_is_null(arglist))
2991 {
2992 #define NARGS 10
2993 Xen args[NARGS * 2];
2994 Xen keys[NARGS];
2995 int orig_arg[NARGS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2996 int vals, i, arglist_len;
2997
2998 if (!Xen_is_keyword(Xen_car(arglist)))
2999 {
3000 object = Xen_car(arglist);
3001 arglist = Xen_cdr(arglist);
3002 }
3003
3004 keys[0] = kw_start;
3005 keys[1] = kw_end;
3006 keys[2] = kw_channel;
3007 keys[3] = kw_edit_position;
3008 keys[4] = kw_out_channel;
3009 keys[5] = kw_with_sync;
3010 keys[6] = kw_wait;
3011 keys[7] = kw_stop;
3012 keys[8] = kw_srate;
3013 keys[9] = kw_channels;
3014
3015 for (i = 0; i < NARGS * 2; i++) args[i] = Xen_undefined;
3016 arglist_len = Xen_list_length(arglist);
3017 if (arglist_len > NARGS)
3018 Xen_out_of_range_error(S_play, 0, arglist, "too many arguments");
3019
3020 for (i = 0; i < arglist_len; i++) args[i] = Xen_list_ref(arglist, i);
3021 vals = mus_optkey_unscramble(S_play, arglist_len, NARGS, keys, args, orig_arg);
3022
3023 if (vals > 0)
3024 {
3025 start = mus_optkey_to_mus_long_t(keys[0], S_play, orig_arg[0], start);
3026 if (start < 0)
3027 Xen_out_of_range_error(S_play, orig_arg[0], keys[0], "start is negative?");
3028
3029 end = mus_optkey_to_mus_long_t(keys[1], S_play, orig_arg[1], end);
3030 if (end < -1)
3031 Xen_out_of_range_error(S_play, orig_arg[1], keys[1], "end is negative?");
3032
3033 channel = mus_optkey_to_int(keys[2], S_play, orig_arg[2], channel);
3034 channel_argpos = orig_arg[2];
3035 channel_arg = keys[2];
3036
3037 if (!(Xen_is_keyword(keys[3])))
3038 {
3039 edit_position = keys[3];
3040 edpos_argpos = orig_arg[3];
3041 }
3042 out_channel = mus_optkey_to_int(keys[4], S_play, orig_arg[4], out_channel);
3043
3044 with_sync = mus_optkey_to_bool(keys[5], S_play, orig_arg[5], with_sync);
3045 wait = mus_optkey_to_bool(keys[6], S_play, orig_arg[6], wait);
3046 stop_func = mus_optkey_to_procedure(keys[7], S_play, orig_arg[7], stop_func, 1, "play stop function takes 1 argument");
3047
3048 srate = mus_optkey_to_int(keys[8], S_play, orig_arg[8], srate);
3049 if (srate <= 0)
3050 Xen_out_of_range_error(S_play, orig_arg[8], keys[8], "srate <= 0?");
3051
3052 channels = mus_optkey_to_int(keys[9], S_play, orig_arg[9], channels);
3053 if (channels <= 0)
3054 Xen_out_of_range_error(S_play, orig_arg[9], keys[9], "channels <= 0?");
3055 }
3056 }
3057 #endif
3058
3059 #if USE_NO_GUI
3060 background = NOT_IN_BACKGROUND;
3061 #else
3062 if (wait) background = NOT_IN_BACKGROUND; else background = IN_BACKGROUND;
3063 /* confusing! wait=#f means don't wait for the play to complete => IN_BACKGROUND */
3064 #endif
3065 /* unspecified object means the current sound, all chans, all samps, with sync, without wait, current edpos */
3066 if (!Xen_is_bound(object))
3067 {
3068 sp = any_selected_sound();
3069 if (sp)
3070 play_sound_1(sp, start, end, background, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), Xen_false, NULL, 0);
3071 return(Xen_false);
3072 }
3073
3074 /* #f object means start sending out zeros */
3075 if (Xen_is_false(object))
3076 return(C_bool_to_Xen_boolean(add_zeros_to_play_list(srate, channels)));
3077
3078 /* procedure object means add that function to the play list */
3079 if (Xen_is_procedure(object))
3080 return(C_bool_to_Xen_boolean(add_xen_to_play_list(object)));
3081
3082 /* mix object */
3083 if (xen_is_mix(object))
3084 return(g_play_mix(object, start));
3085
3086 /* selection object */
3087 if (xen_is_selection(object))
3088 {
3089 if (selection_is_active())
3090 play_selection_1(background, stop_func);
3091 return(object);
3092 }
3093
3094 /* region object */
3095 if (xen_is_region(object))
3096 return(g_play_region(object, background, stop_func));
3097
3098 /* string object = filename */
3099 if (Xen_is_string(object))
3100 {
3101 char *name;
3102 name = mus_expand_filename(Xen_string_to_C_string(object));
3103 play_file((const char *)name, start, end, channel, out_channel, background, stop_func);
3104 free(name);
3105 return(object);
3106 }
3107
3108 /* otherwise object is either a player or a sound */
3109 if (xen_is_player(object))
3110 sp = get_player_sound(object);
3111 else sp = get_sp(object);
3112
3113 if (!sp)
3114 return(snd_no_such_sound_error(S_play, object));
3115
3116 if ((with_sync) &&
3117 (sp->sync != 0) &&
3118 (!(is_player_sound(sp))))
3119 {
3120 sync_info *si;
3121 mus_long_t *ends = NULL;
3122 int i;
3123
3124 si = snd_sync(sp->sync);
3125 if (end != NO_END_SPECIFIED)
3126 {
3127 ends = (mus_long_t *)calloc(si->chans, sizeof(mus_long_t));
3128 for (i = 0; i < si->chans; i++) ends[i] = end;
3129 }
3130 for (i = 0; i < si->chans; i++) si->begs[i] = start;
3131 play_channels_1(si->cps, si->chans, si->begs, ends, background, edit_position, false, stop_func, S_play, edpos_argpos);
3132
3133 free_sync_info(si);
3134 if (ends) free(ends);
3135 return(Xen_false);
3136 }
3137
3138 if (channel == -1)
3139 play_sound_1(sp, start, end, background, edit_position, stop_func, S_play, edpos_argpos);
3140 else
3141 {
3142 if ((channel < (int)(sp->nchans)) &&
3143 (channel >= 0))
3144 {
3145 int pos;
3146 chan_info *cp;
3147 cp = sp->chans[channel];
3148 if (out_channel < 0) out_channel = channel;
3149 pos = to_c_edit_position(cp, edit_position, S_play, edpos_argpos);
3150 play_channel_1(cp, start, end, background, pos, stop_func, out_channel);
3151 }
3152 else Xen_out_of_range_error(S_play, channel_argpos, channel_arg, "channel does not exist?");
3153 }
3154
3155 return(object);
3156 }
3157
3158
3159 Xen no_such_player_error(const char *caller, Xen player)
3160 {
3161 Xen_error(Xen_make_error_type("no-such-player"),
3162 Xen_list_3(C_string_to_Xen_string("~A: no such player, ~A"),
3163 C_string_to_Xen_string(caller),
3164 player));
3165 return(Xen_false);
3166 }
3167
3168
3169 static Xen g_stop_playing(Xen snd)
3170 {
3171 #define H_stop_playing "(" S_stop_playing " :optional snd): stop play (DAC output) in progress"
3172 snd_info *sp = NULL;
3173
3174 Xen_check_type(Xen_is_integer(snd) || xen_is_sound(snd) || !Xen_is_bound(snd) || xen_is_player(snd), snd, 1, S_stop_playing, "a sound or player");
3175
3176 if (Xen_is_integer(snd) || xen_is_sound(snd))
3177 {
3178 sp = get_sp(snd);
3179 if (!sp)
3180 return(snd_no_such_sound_error(S_stop_playing, snd));
3181 }
3182 else
3183 {
3184 if (xen_is_player(snd))
3185 {
3186 sp = get_player_sound(snd);
3187 if (!sp)
3188 return(no_such_player_error(S_stop_playing, snd));
3189 }
3190 }
3191
3192 if (sp)
3193 stop_playing_sound(sp, PLAY_STOP_CALLED);
3194 else stop_playing_all_sounds(PLAY_STOP_CALLED);
3195
3196 return(Xen_false);
3197 }
3198
3199
3200
3201
3202 /* add-player make-player stop-player start-playing */
3203
3204 static Xen g_make_player(Xen snd, Xen chn)
3205 {
3206 #define H_make_player "(" S_make_player " :optional snd chn): \
3207 make a new player associated with snd's channel chn. \
3208 A player is a sort of wrapper for a channel of a sound; it supports \
3209 all the control panel functions. Once created, you can set these \
3210 fields, then call " S_add_player " to add this channel to the list of \
3211 channels either being played (if a play is in progress) or about \
3212 to be played (via " S_start_playing ")."
3213
3214 snd_info *true_sp, *new_sp;
3215 chan_info *cp;
3216
3217 Snd_assert_channel(S_make_player, snd, chn, 1);
3218 true_sp = get_sp(snd);
3219 if (!true_sp)
3220 return(snd_no_such_sound_error(S_make_player, snd));
3221
3222 cp = get_cp(snd, chn, S_make_player);
3223 new_sp = make_snd_info(NULL, "make_player:wrapper", true_sp->hdr, new_player_index(), FILE_READ_ONLY);
3224 new_sp->chans[cp->chan] = cp;
3225
3226 return(C_int_to_Xen_player(make_player(new_sp, cp)));
3227 }
3228
3229
3230 static Xen g_player_home(Xen player)
3231 {
3232 #define H_player_home "(" S_player_home " player): a list of the sound index and channel number associated with player"
3233 int index;
3234
3235 Xen_check_type(xen_is_player(player), player, 1, S_player_home, "a player");
3236 index = Xen_player_to_C_int(player);
3237
3238 if ((index > 0) &&
3239 (index < players_size) &&
3240 (players[index]) &&
3241 (players[index]->chans) &&
3242 (player_chans[index] < (int)players[index]->nchans))
3243 {
3244 chan_info *cp;
3245 cp = players[index]->chans[player_chans[index]]; /* trying to get back to the original sound index (not the player index) */
3246
3247 if ((cp->sound) &&
3248 (cp->sound->active))
3249 return(Xen_list_2(C_int_to_Xen_sound(cp->sound->index),
3250 C_int_to_Xen_integer(cp->chan)));
3251 return(Xen_false); /* can this happen? */
3252 }
3253
3254 return(no_such_player_error(S_player_home, player));
3255 }
3256
3257
3258 static Xen g_add_player(Xen player, Xen start, Xen end, Xen edpos, Xen stop_proc, Xen out_chan)
3259 {
3260 #define H_add_player "(" S_add_player " player :optional (start 0) (end len) (pos -1) stop-proc (out-chan player-chan)): \
3261 adds a player to the play list; the play begins when " S_start_playing " is called. \
3262 The start, end, and edit-position of the portion played can be specified. 'out-chan' is \
3263 the audio hardware output channel to use to play this channel. It defaults to the \
3264 channel number in the sound that contains the channel being played."
3265
3266 snd_info *sp = NULL;
3267 int index, pos;
3268 chan_info *cp;
3269 dac_info *dp = NULL;
3270 int i, ochan = -1;
3271
3272 Xen_check_type(xen_is_player(player), player, 1, S_add_player, "a player");
3273 Xen_check_type(Xen_is_integer_or_unbound(start), start, 2, S_add_player, "an integer");
3274 Xen_check_type(Xen_is_integer_or_unbound(end), end, 3, S_add_player, "an integer");
3275 Xen_check_type(((Xen_is_procedure(stop_proc)) && (procedure_arity_ok(stop_proc, 1))) ||
3276 (!Xen_is_bound(stop_proc)) ||
3277 (Xen_is_false(stop_proc)),
3278 stop_proc, 5, S_add_player, "a procedure of 1 arg");
3279 Xen_check_type(Xen_is_integer_or_unbound(out_chan), out_chan, 6, S_add_player, "an integer");
3280
3281 index = Xen_player_to_C_int(player);
3282 if ((index > 0) && (index < players_size))
3283 sp = players[index];
3284
3285 if (!sp)
3286 return(no_such_player_error(S_add_player, player));
3287
3288 if (play_list)
3289 for (i = 0; i < dac_max_sounds; i++)
3290 if ((play_list[i]) &&
3291 (sp == (play_list[i]->sp)))
3292 Xen_error(Xen_make_error_type("arg-error"),
3293 Xen_list_2(C_string_to_Xen_string(S_add_player ": player ~A is already in the play list"),
3294 player));
3295
3296 cp = sp->chans[player_chans[index]];
3297 pos = to_c_edit_position(cp, edpos, S_add_player, 4);
3298 if (Xen_is_integer(out_chan)) ochan = Xen_integer_to_C_int(out_chan);
3299 if (ochan < 0) ochan = cp->chan;
3300
3301 dp = add_channel_to_play_list(cp,
3302 sp, /* this is not cp->sound! */
3303 beg_to_sample(start, S_add_player),
3304 (Xen_is_llong(end)) ? Xen_llong_to_C_llong(end) : NO_END_SPECIFIED,
3305 pos,
3306 ochan);
3307 if (!dp) return(Xen_false);
3308
3309 dp->stop_procedure = stop_proc;
3310 if (Xen_is_procedure(stop_proc))
3311 dp->stop_procedure_gc_loc = snd_protect(stop_proc);
3312
3313 return(player);
3314 }
3315
3316
3317 static Xen g_start_playing(Xen Chans, Xen Srate, Xen In_Background)
3318 {
3319 #define H_start_playing "(" S_start_playing " :optional (chans 1) (srate 44100) (in-background " PROC_TRUE ")): \
3320 If a play-list is waiting, start it."
3321
3322 int chans = 1, srate = 44100;
3323 bool back;
3324
3325 Xen_check_type(Xen_is_integer_or_unbound(Chans), Chans, 1, S_start_playing, "an integer");
3326 Xen_check_type(Xen_is_integer_or_unbound(Srate), Srate, 2, S_start_playing, "an integer");
3327 Xen_check_type(Xen_is_boolean_or_unbound(In_Background), In_Background, 3, S_start_playing, "a boolean");
3328
3329 if (Xen_is_integer(Chans)) chans = Xen_integer_to_C_int(Chans);
3330 if ((chans <= 0) || (chans > MUS_MAX_CHANS))
3331 Xen_out_of_range_error(S_start_playing, 1, Chans, "chans <= 0 or > 256?");
3332
3333 if (Xen_is_integer(Srate)) srate = Xen_integer_to_C_int(Srate);
3334 if (srate <= 0)
3335 Xen_out_of_range_error(S_start_playing, 2, Srate, "srate <= 0?");
3336
3337 back = Xen_boolean_to_C_bool(In_Background);
3338
3339 start_dac(srate, chans, (back) ? IN_BACKGROUND : NOT_IN_BACKGROUND, DEFAULT_REVERB_CONTROL_DECAY);
3340 return(Xen_false);
3341 }
3342
3343
3344 static Xen g_stop_player(Xen player)
3345 {
3346 #define H_stop_player "(" S_stop_player " player): stop player and remove its associated sound from the current DAC playlist"
3347 snd_info *sp = NULL;
3348
3349 Xen_check_type(xen_is_player(player), player, 1, S_stop_player, "a player");
3350
3351 sp = get_player_sound(player);
3352 if (sp)
3353 stop_playing_sound(sp, PLAY_STOP_CALLED);
3354 return(player);
3355 }
3356
3357
3358 static Xen g_free_player(Xen player)
3359 {
3360 #define H_free_player "(" S_free_player " player): free all resources associated with 'player' and remove it from the current DAC playlist"
3361 snd_info *sp = NULL;
3362
3363 Xen_check_type(xen_is_player(player), player, 1, S_free_player, "a player");
3364
3365 sp = get_player_sound(player);
3366 if (sp)
3367 free_player_sound(sp);
3368 return(Xen_false);
3369 }
3370
3371
3372 /* also the dac filler needs to run on empty buffers in this case? */
3373
3374 static Xen g_is_player(Xen obj)
3375 {
3376 #define H_is_player "(" S_is_player " obj): is 'obj' an active player"
3377 if (xen_is_player(obj))
3378 {
3379 int index;
3380 index = Xen_player_to_C_int(obj);
3381 return(C_bool_to_Xen_boolean((index > 0) &&
3382 (index < players_size) &&
3383 (players[index])));
3384 }
3385 return(Xen_false);
3386 }
3387
3388
3389 /* player-position? -- need quick way from index to dp to its sampler, then C_llong_to_Xen_llong(current_location(fd)) */
3390
3391 static Xen g_players(void)
3392 {
3393 #define H_players "(" S_players ") -> list of currently active players."
3394 Xen lst = Xen_empty_list;
3395 int i;
3396 for (i = 0; i < players_size; i++)
3397 if (players[i])
3398 lst = Xen_cons(C_int_to_Xen_player(i), lst);
3399 return(lst);
3400 }
3401
3402
3403 static Xen g_dac_size(void) {return(C_int_to_Xen_integer(dac_size(ss)));}
3404
3405 static Xen g_set_dac_size(Xen val)
3406 {
3407 #define H_dac_size "(" S_dac_size "): the current DAC buffer size in framples (256)"
3408 int len;
3409 Xen_check_type(Xen_is_integer(val), val, 1, S_set S_dac_size, "an integer");
3410 len = Xen_integer_to_C_int(val);
3411 if (len > 0)
3412 set_dac_size(len); /* macro in snd-0.h */
3413 return(C_int_to_Xen_integer(dac_size(ss)));
3414 }
3415
3416
3417 static Xen g_dac_combines_channels(void) {return(C_bool_to_Xen_boolean(dac_combines_channels(ss)));}
3418
3419 static Xen g_set_dac_combines_channels(Xen val)
3420 {
3421 #define H_dac_combines_channels "(" S_dac_combines_channels "): " PROC_TRUE " if extra channels are to be mixed into available ones during playing. \
3422 That is, if the sound to be played has 4 channels, but the DAC can only handle 2, if this \
3423 variable is " PROC_TRUE ", the extra channels are mixed into the available ones; otherwise they are ignored."
3424
3425 Xen_check_type(Xen_is_boolean(val), val, 1, S_set S_dac_combines_channels, "a boolean");
3426 set_dac_combines_channels(Xen_boolean_to_C_bool(val));
3427 return(C_bool_to_Xen_boolean(dac_combines_channels(ss)));
3428 }
3429
3430
3431 static Xen g_playing(void)
3432 {
3433 #define H_playing "(" S_playing "): " PROC_TRUE " if sound output is in progress. If players are waiting to start, \
3434 setting this to " PROC_TRUE " starts them; setting it to " PROC_FALSE " stops output."
3435 return(C_bool_to_Xen_boolean(something_is_playing()));
3436 }
3437
3438
3439 static Xen g_set_playing(Xen on)
3440 {
3441 bool starting;
3442 Xen_check_type(Xen_is_boolean(on), on, 1, S_set S_playing, "a boolean");
3443 starting = Xen_boolean_to_C_bool(on);
3444 if (starting)
3445 start_dac((int)mus_srate(), 1, IN_BACKGROUND, DEFAULT_REVERB_CONTROL_DECAY); /* how to get plausible srate chans here? */
3446 else stop_playing_all_sounds(PLAY_STOP_CALLED);
3447 return(on);
3448 }
3449
3450
3451 static Xen g_pausing(void)
3452 {
3453 #define H_pausing "(" S_pausing "): " PROC_TRUE " if sound output is currently pausing (this can be set)."
3454 return(C_bool_to_Xen_boolean(dac_pausing));
3455 }
3456
3457
3458 static Xen g_set_pausing(Xen pause)
3459 {
3460 Xen_check_type(Xen_is_boolean(pause), pause, 1, S_set S_pausing, "a boolean");
3461 dac_pausing = Xen_boolean_to_C_bool(pause);
3462 play_button_pause(dac_pausing);
3463 return(pause);
3464 }
3465
3466
3467 static Xen g_cursor_update_interval(void) {return(C_double_to_Xen_real(cursor_update_interval(ss)));}
3468
3469 static Xen g_set_cursor_update_interval(Xen val)
3470 {
3471 mus_float_t ctime;
3472 #define H_cursor_update_interval "(" S_cursor_update_interval "): time (seconds) between cursor updates if " S_with_tracking_cursor "."
3473
3474 Xen_check_type(Xen_is_number(val), val, 1, S_set S_cursor_update_interval, "a number");
3475
3476 ctime = Xen_real_to_C_double(val);
3477 if ((ctime < 0.0) || (ctime > (24 * 3600)))
3478 Xen_out_of_range_error(S_set S_cursor_update_interval, 1, val, "invalid time");
3479 set_cursor_update_interval(ctime);
3480
3481 return(C_double_to_Xen_real(cursor_update_interval(ss)));
3482 }
3483
3484
3485 static Xen g_cursor_location_offset(void) {return(C_int_to_Xen_integer(cursor_location_offset(ss)));}
3486
3487 static Xen g_set_cursor_location_offset(Xen val)
3488 {
3489 int ctime;
3490 #define H_cursor_location_offset "(" S_cursor_location_offset "): samples added to cursor location if cursor displayed during play."
3491
3492 Xen_check_type(Xen_is_integer(val), val, 1, S_set S_cursor_location_offset, "an integer");
3493
3494 ctime = Xen_integer_to_C_int(val);
3495 set_cursor_location_offset(ctime);
3496
3497 return(C_int_to_Xen_integer(cursor_location_offset(ss)));
3498 }
3499
3500
3501 static Xen g_with_tracking_cursor(void)
3502 {
3503 #define H_with_tracking_cursor "(" S_with_tracking_cursor "): " PROC_TRUE " if cursor always moves along in waveform display as sound is played"
3504 if (with_tracking_cursor(ss) == DONT_TRACK)
3505 return(Xen_false);
3506 if (with_tracking_cursor(ss) == TRACK_AND_RETURN)
3507 return(Xen_true);
3508 return(Xen_make_keyword("track-and-stay"));
3509 }
3510
3511 static Xen g_set_with_tracking_cursor(Xen on)
3512 {
3513 if (Xen_is_boolean(on)) /* for backwards compatibility */
3514 {
3515 set_with_tracking_cursor(ss, (Xen_boolean_to_C_bool(on)) ? TRACK_AND_RETURN : DONT_TRACK);
3516 return(on);
3517 }
3518
3519 if (Xen_is_integer(on))
3520 {
3521 int val;
3522 val = Xen_integer_to_C_int(on);
3523 if (val == 2)
3524 set_with_tracking_cursor(ss, TRACK_AND_STAY);
3525 else set_with_tracking_cursor(ss, ((val == 1) ? TRACK_AND_RETURN : DONT_TRACK));
3526 return(C_int_to_Xen_integer((int)with_tracking_cursor(ss)));
3527 }
3528
3529 if (Xen_is_keyword(on))
3530 {
3531 if (Xen_keyword_is_eq(on, Xen_make_keyword("track-and-return")))
3532 {
3533 set_with_tracking_cursor(ss, TRACK_AND_RETURN);
3534 return(on);
3535 }
3536 if (Xen_keyword_is_eq(on, Xen_make_keyword("track-and-stay")))
3537 {
3538 set_with_tracking_cursor(ss, TRACK_AND_STAY);
3539 return(on);
3540 }
3541 if (Xen_keyword_is_eq(on, Xen_make_keyword("dont-track")))
3542 {
3543 set_with_tracking_cursor(ss, DONT_TRACK);
3544 return(on);
3545 }
3546 }
3547
3548 Xen_check_type(false, on, 1, S_set S_with_tracking_cursor, ":dont-track, :track-and-return, or :track-and-stay");
3549 return(on);
3550 }
3551
3552
3553
3554
3555
3556 Xen_wrap_no_args(g_with_tracking_cursor_w, g_with_tracking_cursor)
3557 Xen_wrap_1_arg(g_set_with_tracking_cursor_w, g_set_with_tracking_cursor)
3558 #if (!HAVE_SCHEME)
3559 Xen_wrap_any_args(g_play_w, g_play)
3560 #endif
3561 Xen_wrap_1_optional_arg(g_stop_playing_w, g_stop_playing)
3562 Xen_wrap_2_optional_args(g_make_player_w, g_make_player)
3563 Xen_wrap_6_optional_args(g_add_player_w, g_add_player)
3564 Xen_wrap_1_arg(g_player_home_w, g_player_home)
3565 Xen_wrap_3_optional_args(g_start_playing_w, g_start_playing)
3566 Xen_wrap_1_arg(g_stop_player_w, g_stop_player)
3567 Xen_wrap_1_arg(g_free_player_w, g_free_player)
3568 Xen_wrap_no_args(g_players_w, g_players)
3569 Xen_wrap_1_arg(g_is_player_w, g_is_player)
3570 Xen_wrap_no_args(g_dac_size_w, g_dac_size)
3571 Xen_wrap_1_arg(g_set_dac_size_w, g_set_dac_size)
3572 Xen_wrap_no_args(g_dac_combines_channels_w, g_dac_combines_channels)
3573 Xen_wrap_1_arg(g_set_dac_combines_channels_w, g_set_dac_combines_channels)
3574 Xen_wrap_no_args(g_playing_w, g_playing)
3575 Xen_wrap_1_arg(g_set_playing_w, g_set_playing)
3576 Xen_wrap_no_args(g_pausing_w, g_pausing)
3577 Xen_wrap_1_arg(g_set_pausing_w, g_set_pausing)
3578 Xen_wrap_no_args(g_cursor_update_interval_w, g_cursor_update_interval)
3579 Xen_wrap_1_arg(g_set_cursor_update_interval_w, g_set_cursor_update_interval)
3580 Xen_wrap_no_args(g_cursor_location_offset_w, g_cursor_location_offset)
3581 Xen_wrap_1_arg(g_set_cursor_location_offset_w, g_set_cursor_location_offset)
3582
3583 #if HAVE_SCHEME
3584 static s7_pointer acc_cursor_location_offset(s7_scheme *sc, s7_pointer args) {return(g_set_cursor_location_offset(s7_cadr(args)));}
3585 static s7_pointer acc_cursor_update_interval(s7_scheme *sc, s7_pointer args) {return(g_set_cursor_update_interval(s7_cadr(args)));}
3586 static s7_pointer acc_dac_combines_channels(s7_scheme *sc, s7_pointer args) {return(g_set_dac_combines_channels(s7_cadr(args)));}
3587 static s7_pointer acc_dac_size(s7_scheme *sc, s7_pointer args) {return(g_set_dac_size(s7_cadr(args)));}
3588 static s7_pointer acc_with_tracking_cursor(s7_scheme *sc, s7_pointer args) {return(g_set_with_tracking_cursor(s7_cadr(args)));}
3589 #endif
3590
3591 void g_init_dac(void)
3592 {
3593 #if HAVE_SCHEME
3594 s7_pointer i, b, p, t, r, pl, l, pcl_t;
3595 i = s7_make_symbol(s7, "integer?");
3596 b = s7_make_symbol(s7, "boolean?");
3597 p = s7_make_symbol(s7, "pair?");
3598 l = s7_make_symbol(s7, "list?");
3599 r = s7_make_symbol(s7, "real?");
3600 pl = s7_make_symbol(s7, "player?");
3601 t = s7_t(s7);
3602 pcl_t = s7_make_circular_signature(s7, 0, 1, t);
3603 #endif
3604
3605 init_xen_player();
3606 #if (!HAVE_SCHEME)
3607 init_play_keywords();
3608 Xen_define_typed_procedure(S_play, g_play_w, 0, 0, 1, H_play, pcl_t);
3609 #else
3610 s7_define_function_star(s7, S_play, g_play, "(object #<undefined>) start end channel edit-position out-channel with-sync wait stop srate channels", H_play);
3611 #endif
3612
3613 Xen_define_typed_procedure(S_stop_playing, g_stop_playing_w, 0, 1, 0, H_stop_playing, s7_make_signature(s7, 2, b, t));
3614 Xen_define_typed_procedure(S_make_player, g_make_player_w, 0, 2, 0, H_make_player, s7_make_signature(s7, 3, pl, t, t));
3615 Xen_define_typed_procedure(S_add_player, g_add_player_w, 1, 5, 0, H_add_player, s7_make_signature(s7, 7, pl, pl, i, i, t, t, i));
3616 Xen_define_typed_procedure(S_player_home, g_player_home_w, 1, 0, 0, H_player_home, s7_make_signature(s7, 2, p, pl));
3617 Xen_define_typed_procedure(S_start_playing, g_start_playing_w, 0, 3, 0, H_start_playing, s7_make_signature(s7, 4, b, i, i, b));
3618 Xen_define_typed_procedure(S_stop_player, g_stop_player_w, 1, 0, 0, H_stop_player, s7_make_signature(s7, 2, pl, pl));
3619 Xen_define_typed_procedure(S_free_player, g_free_player_w, 1, 0, 0, H_free_player, s7_make_signature(s7, 2, b, pl));
3620 Xen_define_typed_procedure(S_players, g_players_w, 0, 0, 0, H_players, s7_make_signature(s7, 1, l));
3621 Xen_define_typed_procedure(S_is_player, g_is_player_w, 1, 0, 0, H_is_player, s7_make_signature(s7, 2, b, t));
3622
3623 Xen_define_typed_dilambda(S_pausing, g_pausing_w, H_pausing,
3624 S_set S_pausing, g_set_pausing_w, 0, 0, 1, 0,
3625 s7_make_signature(s7, 1, b), s7_make_signature(s7, 2, b, b));
3626
3627 Xen_define_typed_dilambda(S_playing, g_playing_w, H_playing,
3628 S_set S_playing, g_set_playing_w, 0, 0, 1, 0,
3629 s7_make_signature(s7, 1, b), s7_make_signature(s7, 2, b, b));
3630
3631 Xen_define_typed_dilambda(S_with_tracking_cursor, g_with_tracking_cursor_w, H_with_tracking_cursor,
3632 S_set S_with_tracking_cursor, g_set_with_tracking_cursor_w, 0, 0, 1, 0,
3633 pcl_t, pcl_t);
3634
3635 Xen_define_typed_dilambda(S_dac_size, g_dac_size_w, H_dac_size,
3636 S_set S_dac_size, g_set_dac_size_w, 0, 0, 1, 0,
3637 s7_make_signature(s7, 1, i), s7_make_signature(s7, 2, i, i));
3638
3639 Xen_define_typed_dilambda(S_dac_combines_channels, g_dac_combines_channels_w, H_dac_combines_channels,
3640 S_set S_dac_combines_channels, g_set_dac_combines_channels_w, 0, 0, 1, 0,
3641 s7_make_signature(s7, 1, b), s7_make_signature(s7, 2, b, b));
3642
3643 Xen_define_typed_dilambda(S_cursor_update_interval, g_cursor_update_interval_w, H_cursor_update_interval,
3644 S_set S_cursor_update_interval, g_set_cursor_update_interval_w, 0, 0, 1, 0,
3645 s7_make_signature(s7, 1, r), s7_make_signature(s7, 2, r, r));
3646
3647 Xen_define_typed_dilambda(S_cursor_location_offset, g_cursor_location_offset_w, H_cursor_location_offset,
3648 S_set S_cursor_location_offset, g_set_cursor_location_offset_w, 0, 0, 1, 0,
3649 s7_make_signature(s7, 1, i), s7_make_signature(s7, 2, i, i));
3650
3651
3652 #define H_stop_playing_hook S_stop_playing_hook " (snd): called when a sound finishes playing."
3653 #define H_play_hook S_play_hook " (size): called each time a buffer is sent to the DAC."
3654 #define H_start_playing_hook S_start_playing_hook " (snd): called when a play request is triggered. \
3655 If it returns " PROC_TRUE ", the sound is not played."
3656
3657 #define H_stop_playing_selection_hook S_stop_playing_selection_hook " (): called when the selection stops playing"
3658 #define H_start_playing_selection_hook S_start_playing_selection_hook " (): called when the selection starts playing"
3659
3660 stop_playing_hook = Xen_define_hook(S_stop_playing_hook, "(make-hook 'snd)", 1, H_stop_playing_hook);
3661 start_playing_hook = Xen_define_hook(S_start_playing_hook, "(make-hook 'snd)", 1, H_start_playing_hook);
3662 play_hook = Xen_define_hook(S_play_hook, "(make-hook 'size)", 1, H_play_hook);
3663 stop_playing_selection_hook = Xen_define_hook(S_stop_playing_selection_hook, "(make-hook)", 0, H_stop_playing_selection_hook);
3664 start_playing_selection_hook = Xen_define_hook(S_start_playing_selection_hook, "(make-hook)", 0, H_start_playing_selection_hook);
3665
3666 #if HAVE_SCHEME
3667 s7_set_setter(s7, ss->cursor_location_offset_symbol, s7_make_function(s7, "[acc-" S_cursor_location_offset "]", acc_cursor_location_offset, 2, 0, false, "accessor"));
3668 s7_set_setter(s7, ss->cursor_update_interval_symbol, s7_make_function(s7, "[acc-" S_cursor_update_interval "]", acc_cursor_update_interval, 2, 0, false, "accessor"));
3669 s7_set_setter(s7, ss->dac_combines_channels_symbol, s7_make_function(s7, "[acc-" S_dac_combines_channels "]", acc_dac_combines_channels, 2, 0, false, "accessor"));
3670 s7_set_setter(s7, ss->dac_size_symbol, s7_make_function(s7, "[acc-" S_dac_size "]", acc_dac_size, 2, 0, false, "accessor"));
3671 s7_set_setter(s7, ss->with_tracking_cursor_symbol, s7_make_function(s7, "[acc-" S_with_tracking_cursor "]", acc_with_tracking_cursor, 2, 0, false, "accessor"));
3672
3673 s7_set_documentation(s7, ss->cursor_location_offset_symbol, "*cursor-location-offset*: samples added to cursor location if cursor displayed during play.");
3674 s7_set_documentation(s7, ss->cursor_update_interval_symbol, "*cursor-update-interval*: time (seconds) between cursor updates if with-tracking-cursor.");
3675 s7_set_documentation(s7, ss->dac_combines_channels_symbol, "*dac-combines-channels*: #t if extra channels are to be mixed into available ones during playing.");
3676 s7_set_documentation(s7, ss->dac_size_symbol, "*dac-size*: the current DAC buffer size in framples (256)");
3677 s7_set_documentation(s7, ss->with_tracking_cursor_symbol, "*with-tracking-cursor*: #t if cursor always moves along in waveform display as sound is played");
3678 #endif
3679 }
3680
3681 /* dac loop [need start/end of loop in dac_info, reader goes to start when end reached (requires rebuffering)
3682 * looper does not stop/restart -- just keep going]
3683 * play_selection_1 could put ends somewhere, set ends to NO_END_SPECIFIED, dac_loop_sample can
3684 * use begs/other-ends to get loop points, so free_dac_info does not need to restart the loop(?)
3685 * If start/end selection changed while playing, are these loop points updated?
3686 */
3687