1 #include "snd.h"
2 
3 
make_chan_info(chan_info * cip,int chan,snd_info * sound)4 chan_info *make_chan_info(chan_info *cip, int chan, snd_info *sound)
5 {
6   chan_info *cp; /* may be re-used */
7   if (!cip)
8     {
9       cp = (chan_info *)calloc(1, sizeof(chan_info));
10       cp->ax = (graphics_context *)calloc(1, sizeof(graphics_context));
11 
12       switch (chan % 4)
13 	{
14 	case 0: cp->combined_data_color = ss->black;      break;
15 	case 1: cp->combined_data_color = ss->red;        break;
16 	case 2: cp->combined_data_color = ss->green;      break;
17 	case 3: cp->combined_data_color = ss->blue;       break;
18 	}
19       cp->last_sonogram = NULL;
20       cp->last_wavogram = NULL;
21       cp->temp_sonogram = NULL;
22       cp->inset_graph = NULL;
23       cp->fft = NULL;
24 #if HAVE_GL
25       cp->gl_fft_list = NO_LIST;
26       cp->gl_wavo_list = NO_LIST;
27 #endif
28       cp->edit_hook = Xen_false;
29       cp->edit_hook_loc = NOT_A_GC_LOC;
30       cp->after_edit_hook = Xen_false;
31       cp->after_edit_hook_loc = NOT_A_GC_LOC;
32       cp->undo_hook = Xen_false;
33       cp->undo_hook_loc = NOT_A_GC_LOC;
34       cp->properties = Xen_false; /* will be a vector of 1 element if it's ever used */
35       cp->properties_loc = NOT_A_GC_LOC;
36       cp->active = CHANNEL_INACTIVE;
37     }
38   else cp = cip;
39   cp->chan = chan;
40   cp->sound = sound;
41   cp->sound_ctr = NOT_A_SOUND;
42   cp->edit_ctr = -1;
43   cp->sound_size = 0;
44   cp->edit_size = 0;
45   cp->cursor_on = false;
46   cp->cursor_visible = false;
47   cp->fft_cursor_visible = false;
48   cp->show_sonogram_cursor = show_sonogram_cursor(ss);
49   cp->selection_visible = false;
50   cp->editable = true; /* must be unset (region display, variable display, etc) */
51   cp->cursor_style = cursor_style(ss);
52   cp->tracking_cursor_style = tracking_cursor_style(ss);
53   cp->cursor_size = cursor_size(ss);
54   cp->cursor_proc = Xen_undefined;
55   cp->cursor_proc_loc = NOT_A_GC_LOC;
56   cp->squelch_update = false;
57   cp->show_y_zero = show_y_zero(ss);
58   cp->show_grid = show_grid(ss);
59   cp->show_marks = show_marks(ss);
60   cp->time_graph_type = time_graph_type(ss);
61   cp->wavo_hop = wavo_hop(ss);
62   cp->wavo_trace = wavo_trace(ss);
63   cp->max_transform_peaks = max_transform_peaks(ss);
64   cp->show_transform_peaks = show_transform_peaks(ss);
65   cp->zero_pad = zero_pad(ss);
66   cp->with_verbose_cursor = with_verbose_cursor(ss);
67   cp->fft_log_frequency = fft_log_frequency(ss);
68   cp->fft_log_magnitude = fft_log_magnitude(ss);
69   cp->fft_with_phases = fft_with_phases(ss);
70   cp->min_dB = min_dB(ss);
71   cp->lin_dB = ss->lin_dB;
72   cp->in_as_one_edit = 0;
73   cp->wavelet_type = wavelet_type(ss);
74   cp->spectro_x_angle = spectro_x_angle(ss);
75   cp->spectro_y_angle = spectro_y_angle(ss);
76   cp->spectro_z_angle = spectro_z_angle(ss);
77   cp->spectro_x_scale = spectro_x_scale(ss);
78   cp->spectro_y_scale = spectro_y_scale(ss);
79   cp->spectro_z_scale = spectro_z_scale(ss);
80   cp->spectrum_end = spectrum_end(ss);
81   cp->spectrum_start = spectrum_start(ss);
82   cp->spectro_hop = spectro_hop(ss);
83   cp->fft_window_alpha = fft_window_alpha(ss);
84   cp->fft_window_beta = fft_window_beta(ss);
85   cp->transform_size = transform_size(ss);
86   cp->transform_graph_type = transform_graph_type(ss);
87   cp->fft_window = fft_window(ss);
88   cp->transform_type = transform_type(ss);
89   cp->transform_normalization = transform_normalization(ss);
90   cp->show_mix_waveforms = show_mix_waveforms(ss);
91   cp->time_graph_style = graph_style(ss);
92   cp->lisp_graph_style = graph_style(ss);
93   cp->transform_graph_style = graph_style(ss);
94   cp->graphs_horizontal = graphs_horizontal(ss);
95   cp->dot_size = dot_size(ss);
96   cp->grid_density = grid_density(ss);
97   cp->x_axis_style = x_axis_style(ss);
98   cp->beats_per_minute = beats_per_minute(ss);
99   cp->beats_per_measure = beats_per_measure(ss);
100   cp->show_axes = show_axes(ss);
101   cp->graph_time_on = true; /* the default state (button is set when we start) */
102   cp->graph_transform_on = false;
103   cp->printing = NOT_PRINTING;
104   cp->waiting_to_make_graph = false;
105   cp->new_peaks = false;
106   cp->sonogram_data = NULL;
107   cp->lisp_info = NULL;
108   cp->amp_control = NULL;
109   cp->hookable = WITH_HOOK;
110   cp->cx = 0;
111   cp->cy = 0;
112   cp->fft_cx = 0;
113   cp->selection_transform_size = 0;
114   if (cp->last_sonogram)
115     {
116       free(cp->last_sonogram);
117       cp->last_sonogram = NULL;
118     }
119   if (cp->last_wavogram)
120     {
121       free(cp->last_wavogram);
122       cp->last_wavogram = NULL;
123     }
124   if (cp->inset_graph)
125     clear_inset_graph(cp);
126   cp->active = CHANNEL_INITIALIZED;
127   return(cp);
128 }
129 
130 
free_chan_info(chan_info * cp)131 static chan_info *free_chan_info(chan_info *cp)
132 {
133   /* this does not free the associated widgets -- they are merely unmanaged */
134 
135   cp->active = CHANNEL_INACTIVE;
136   /* need an indication right away that this channel is being deleted -- during free_snd_info (close-sound),
137    *   an error may occur (an edit list temp file might have vanished for example), and normally Snd
138    *   attempts to post an error message in the sound's status area.  To force this out, we have to
139    *   call XmUpdate or equivalent, which can cause all the sound's channels to attempt to redisplay;
140    *   since the one causing the error is half-deallocated, trouble can ensue.  So both the channel
141    *   and the sound have "active" flags that are true only when everything is ship-shape.
142    */
143   chan_info_cleanup(cp);
144   cp->squelch_update = true;
145   cp->axis = free_axis_info(cp->axis);
146   if (cp->fft) cp->fft = free_fft_info(cp->fft);
147   cp_free_fft_state(cp);
148   cp->graph_transform_on = false;
149   cp->printing = NOT_PRINTING;
150   cp->graph_time_on = true;
151   if (cp->edits) free_edit_list(cp);
152   if (cp->sounds) free_sound_list(cp);
153   free_channel_mixes(cp);
154   cp->sound = NULL;  /* a backpointer */
155   cp->cursor_on = false;
156   cp->cursor_visible = false;
157   cp->fft_cursor_visible = false;
158   cp->show_sonogram_cursor = false;
159   cp->selection_visible = false;
160   if (cp->amp_control)
161     {
162       /* not sure this is the right thing */
163       free(cp->amp_control);
164       cp->amp_control = NULL;
165     }
166   if (Xen_is_procedure(cp->cursor_proc))
167     {
168       snd_unprotect_at(cp->cursor_proc_loc);
169       cp->cursor_proc = Xen_undefined;
170       cp->cursor_proc_loc = NOT_A_GC_LOC;
171     }
172   if (Xen_is_vector(cp->properties)) /* using vector as node for GC */
173     Xen_vector_set(cp->properties, 0, Xen_empty_list);
174   cp->waiting_to_make_graph = false;
175   if (cp->sonogram_data) free_sono_info(cp);
176   if (cp->temp_sonogram)
177     {
178       /* special case -- background fft process never got a chance to run */
179       if (cp->temp_sonogram == cp->last_sonogram) cp->last_sonogram = NULL;
180       free_sonogram_fft_state(cp->temp_sonogram);
181       free(cp->temp_sonogram);
182       cp->temp_sonogram = NULL;
183     }
184   if (cp->last_sonogram)
185     {
186       free_sonogram_fft_state(cp->last_sonogram);
187       free(cp->last_sonogram);
188       cp->last_sonogram = NULL;
189     }
190   if (cp->last_wavogram)
191     {
192       free(cp->last_wavogram);
193       cp->last_wavogram = NULL;
194     }
195   if (cp->lisp_info)
196     {
197       free_lisp_info(cp);
198       cp->lisp_info = NULL;
199     }
200   cp->graph_lisp_on = false;
201   cp->selection_transform_size = 0;
202 
203   if (cp->as_one_edit_positions)
204     {
205       free(cp->as_one_edit_positions);
206       cp->as_one_edit_positions = NULL;
207       cp->as_one_edit_positions_size = 0;
208     }
209 
210   if (Xen_is_hook(cp->edit_hook))
211     {
212       Xen_clear_hook_list(cp->edit_hook);
213       snd_unprotect_at(cp->edit_hook_loc);
214       cp->edit_hook = Xen_false;
215       cp->edit_hook_loc = NOT_A_GC_LOC;
216     }
217   if (Xen_is_hook(cp->after_edit_hook))
218     {
219       Xen_clear_hook_list(cp->after_edit_hook);
220       snd_unprotect_at(cp->after_edit_hook_loc);
221       cp->after_edit_hook = Xen_false;
222       cp->after_edit_hook_loc = NOT_A_GC_LOC;
223     }
224   if (Xen_is_hook(cp->undo_hook))
225     {
226       Xen_clear_hook_list(cp->undo_hook);
227       snd_unprotect_at(cp->undo_hook_loc);
228       cp->undo_hook = Xen_false;
229       cp->undo_hook_loc = NOT_A_GC_LOC;
230     }
231   if (cp->inset_graph)
232     clear_inset_graph(cp);
233 
234   return(cp);  /* pointer is left for possible future re-use */
235 }
236 
237 
make_basic_snd_info(int chans)238 snd_info *make_basic_snd_info(int chans)
239 {
240   snd_info *sp;
241   sp = (snd_info *)calloc(1, sizeof(snd_info));
242   sp->chans = (chan_info **)calloc(chans, sizeof(chan_info *));
243   sp->allocated_chans = chans;
244   sp->properties = Xen_false; /* will be a vector of 1 element if it's ever used */
245   sp->properties_loc = NOT_A_GC_LOC;
246 #if USE_NO_GUI
247   sp->widgets = false; /* it's a bool if no gui */
248 #endif
249   return(sp);
250 }
251 
252 
initialize_control_panel(snd_info * sp)253 void initialize_control_panel(snd_info *sp)
254 {
255   sp->expand_control = DEFAULT_EXPAND_CONTROL;
256   sp->expand_control_min = expand_control_min(ss);
257   sp->expand_control_max = expand_control_max(ss);
258   sp->last_expand_control = 0.0;
259   sp->saved_expand_control = 0.0;
260   sp->expand_control_on = DEFAULT_EXPAND_CONTROL_ON;
261   sp->amp_control = DEFAULT_AMP_CONTROL;
262   sp->amp_control_min = amp_control_min(ss);
263   sp->amp_control_max = amp_control_max(ss);
264   sp->last_amp_control = 1.0;
265   sp->saved_amp_control = 1.0;
266   sp->speed_control = fabs(DEFAULT_SPEED_CONTROL);
267   sp->speed_control_min = speed_control_min(ss);
268   sp->speed_control_max = speed_control_max(ss);
269   sp->last_speed_control = 1.0;
270   sp->saved_speed_control = 1.0;
271   if (DEFAULT_SPEED_CONTROL > 0.0) sp->speed_control_direction = 1; else sp->speed_control_direction = -1;
272   sp->contrast_control_on = DEFAULT_CONTRAST_CONTROL_ON;
273   sp->contrast_control = DEFAULT_CONTRAST_CONTROL;
274   sp->contrast_control_min = contrast_control_min(ss);
275   sp->contrast_control_max = contrast_control_max(ss);
276   sp->contrast_control_amp = contrast_control_amp(ss);
277   sp->last_contrast_control = contrast_control_min(ss);
278   sp->saved_contrast_control = contrast_control_min(ss);
279   sp->reverb_control_on = DEFAULT_REVERB_CONTROL_ON;
280   sp->filter_control_on = DEFAULT_FILTER_CONTROL_ON;
281   sp->expand_control_length = expand_control_length(ss);
282   sp->expand_control_ramp = expand_control_ramp(ss);
283   sp->expand_control_hop = expand_control_hop(ss);
284   sp->expand_control_jitter = expand_control_jitter(ss);
285   sp->reverb_control_feedback = reverb_control_feedback(ss);
286   sp->reverb_control_lowpass = reverb_control_lowpass(ss);
287   sp->reverb_control_scale = DEFAULT_REVERB_CONTROL_SCALE;
288   sp->reverb_control_scale_min = reverb_control_scale_min(ss);
289   sp->reverb_control_scale_max = reverb_control_scale_max(ss);
290   sp->reverb_control_decay = reverb_control_decay(ss);
291   sp->speed_control_tones = speed_control_tones(ss);
292   sp->speed_control_style = speed_control_style(ss);
293   sp->speed_control_numerator = 1;
294   sp->speed_control_denominator = 1;
295   sp->last_reverb_control_scale = 0.0;
296   sp->saved_reverb_control_scale = 0.0;
297   sp->reverb_control_length = DEFAULT_REVERB_CONTROL_LENGTH;
298   sp->reverb_control_length_min = reverb_control_length_min(ss);
299   sp->reverb_control_length_max = reverb_control_length_max(ss);
300   sp->last_reverb_control_length = 0.0;
301   sp->saved_reverb_control_length = 0.0;
302   sp->filter_control_order = filter_control_order(ss);
303   sp->filter_control_in_dB = filter_control_in_dB(ss);
304   sp->filter_control_in_hz = filter_control_in_hz(ss);
305   if (sp->filter_control_in_hz)
306     sp->filter_control_xmax = (mus_float_t)(snd_srate(sp) / 2);
307   else sp->filter_control_xmax = 1.0;
308   sp->filter_control_changed = false;
309   sp->saved_controls = NULL;
310 }
311 
312 
make_snd_info(snd_info * sip,const char * filename,file_info * hdr,int snd_slot,read_only_t read_only)313 snd_info *make_snd_info(snd_info *sip, const char *filename, file_info *hdr, int snd_slot, read_only_t read_only)
314 {
315   snd_info *sp = NULL;
316   int chans, i;
317   /* assume file has been found and header read before reaching us */
318   /* if a reused pointer, may need to extend current chans array */
319   chans = hdr->chans;
320   if (!sip)
321     {
322       sp = make_basic_snd_info(chans);
323     }
324   else
325     {
326       sp = sip;
327       if (sp->allocated_chans < chans)
328 	{
329 	  sp->chans = (chan_info **)realloc(sp->chans, chans * sizeof(chan_info *));
330 	  for (i = sp->allocated_chans; i < chans; i++) sp->chans[i] = NULL;
331 	  sp->allocated_chans = chans;
332 	}
333     }
334   sp->user_read_only = read_only;  /* need to be sure this is set before any hooks run */
335   sp->bomb_in_progress = false;
336   sp->index = snd_slot;
337   sp->nchans = chans;
338   sp->hdr = hdr;
339   sp->inuse = SOUND_NORMAL;
340   sp->filename = mus_strdup(filename);
341   sp->short_filename = filename_without_directory(sp->filename); /* a pointer into filename, not a new string */
342   sp->sync = DEFAULT_SYNC;
343   sp->previous_sync = sp->sync;
344   initialize_control_panel(sp);
345   sp->selectpos = -1;
346 
347   if (chans > 1)
348     {
349       if (ss->update_sound_channel_style != NOT_A_CHANNEL_STYLE)
350 	{
351 	  sp->channel_style = ss->update_sound_channel_style;
352 	  ss->update_sound_channel_style = NOT_A_CHANNEL_STYLE;
353 	}
354       else sp->channel_style = channel_style(ss);
355     }
356   else sp->channel_style = CHANNELS_SEPARATE;
357 
358   sp->selected_channel = NO_SELECTION;
359   sp->playing = 0;
360   sp->applying = false;
361   sp->lacp = NULL;
362   sp->delete_me = NULL;
363   sp->name_string = NULL;
364   sp->active = true;
365   return(sp);
366 }
367 
368 
free_snd_info(snd_info * sp)369 void free_snd_info(snd_info *sp)
370 {
371   uint32_t i;
372 
373 #if (!USE_NO_GUI)
374   env_editor *edp;
375 
376   /* make sure trough colors are ok upon reuse */
377   if (sp->reverb_control_on != DEFAULT_REVERB_CONTROL_ON)
378     toggle_reverb_button(sp, DEFAULT_REVERB_CONTROL_ON);
379   if (sp->expand_control_on != DEFAULT_EXPAND_CONTROL_ON)
380     toggle_expand_button(sp, DEFAULT_EXPAND_CONTROL_ON);
381   if (sp->contrast_control_on != DEFAULT_CONTRAST_CONTROL_ON)
382     toggle_contrast_button(sp, DEFAULT_CONTRAST_CONTROL_ON);
383 
384   edp = sp->flt;
385   if (edp)
386     {
387       edp->edited = false;
388       edp->env_dragged = false;
389       edp->env_pos = 0;
390       edp->click_to_delete = false;
391     }
392   set_filter_text(sp, "");
393 #endif
394 
395   /* leave most for reuse as in free_chan_info */
396   sp->active = false;
397   sp->selectpos = -1;
398   sp->sync = 0;
399   snd_info_cleanup(sp);
400   sp->previous_sync = sp->sync;
401   for (i = 0; i < sp->nchans; i++)
402     if (sp->chans[i])
403       sp->chans[i] = free_chan_info(sp->chans[i]);
404   sp->inuse = SOUND_IDLE;
405   sp->playing = 0;
406   sp->bomb_in_progress = false;
407   sp->applying = false;
408   sp->channel_style = CHANNELS_SEPARATE;
409   sp->user_read_only = FILE_READ_WRITE;
410   sp->file_read_only = FILE_READ_WRITE;
411   sp->need_update = false;
412   sp->file_unreadable = false;
413   if (Xen_is_vector(sp->properties)) /* using vector as node for GC */
414     Xen_vector_set(sp->properties, 0, Xen_empty_list);
415   sp->selected_channel = NO_SELECTION;
416   sp->short_filename = NULL;                      /* was a pointer into filename */
417   if (sp->filename) free(sp->filename);
418   sp->filename = NULL;
419   if (sp->filter_control_envelope) sp->filter_control_envelope = free_env(sp->filter_control_envelope);
420   if (sp->saved_controls) free_controls(sp);
421   sp->delete_me = NULL;
422   if (sp->name_string) free(sp->name_string);
423   sp->name_string = NULL;
424   sp->lacp = NULL;
425   sp->hdr = free_file_info(sp->hdr);
426   if (sp->edited_region) clear_region_backpointer(sp);
427   clear_players();
428   reflect_mix_change(ANY_MIX_ID);
429 
430   if (Xen_hook_has_list(ss->effects_hook))
431     run_hook(ss->effects_hook, Xen_empty_list, S_effects_hook);
432 }
433 
434 
completely_free_snd_info(snd_info * sp)435 snd_info *completely_free_snd_info(snd_info *sp)
436 {
437   int i;
438 
439   free_snd_info(sp);
440   for (i = 0; i < sp->allocated_chans; i++)
441     {
442       chan_info *cp;
443       cp = sp->chans[i];
444       if (cp)
445 	{
446 	  if (Xen_is_vector(cp->properties))
447 	    {
448 	      snd_unprotect_at(cp->properties_loc);
449 	      cp->properties_loc = NOT_A_GC_LOC;
450 	    }
451 	  if (cp->inset_graph)
452 	    free_inset_graph(cp);
453 
454 	  cp->active = CHANNEL_FREED;
455 	  free(cp);
456 	  /* it's possible to have dangling readers (snd_fd) with pointers to this channel (see note in snd-edits.c under unlist_reader) */
457 	}
458     }
459   free(sp->chans);
460   if (Xen_is_vector(sp->properties))
461     {
462       snd_unprotect_at(sp->properties_loc);
463       sp->properties_loc = NOT_A_GC_LOC;
464     }
465   free(sp);
466   return(NULL);
467 }
468 
469 
for_each_chan_with_int(void (* func)(chan_info * ncp,int val),int value)470 void for_each_chan_with_int(void (*func)(chan_info *ncp, int val), int value)
471 {
472   int i;
473   for (i = 0; i < ss->max_sounds; i++)
474     {
475       uint32_t j;
476       snd_info *sp;
477       chan_info *cp;
478       sp = ss->sounds[i];
479       if ((sp) && ((sp->inuse == SOUND_NORMAL) || (sp->inuse == SOUND_WRAPPER)))
480 	for (j = 0; j < sp->nchans; j++)
481 	  if ((cp = ((chan_info *)(sp->chans[j]))))
482 	    (*func)(cp, value);
483     }
484 }
485 
486 
for_each_chan_with_mus_long_t(void (* func)(chan_info * ncp,mus_long_t val),mus_long_t value)487 void for_each_chan_with_mus_long_t(void (*func)(chan_info *ncp, mus_long_t val), mus_long_t value)
488 {
489   int i;
490   for (i = 0; i < ss->max_sounds; i++)
491     {
492       uint32_t j;
493       snd_info *sp;
494       chan_info *cp;
495       sp = ss->sounds[i];
496       if ((sp) && ((sp->inuse == SOUND_NORMAL) || (sp->inuse == SOUND_WRAPPER)))
497 	for (j = 0; j < sp->nchans; j++)
498 	  if ((cp = ((chan_info *)(sp->chans[j]))))
499 	    (*func)(cp, value);
500     }
501 }
502 
503 
for_each_chan_with_bool(void (* func)(chan_info * ncp,bool val),bool value)504 void for_each_chan_with_bool(void (*func)(chan_info *ncp, bool val), bool value)
505 {
506   int i;
507   for (i = 0; i < ss->max_sounds; i++)
508     {
509       uint32_t j;
510       snd_info *sp;
511       chan_info *cp;
512       sp = ss->sounds[i];
513       if ((sp) && ((sp->inuse == SOUND_NORMAL) || (sp->inuse == SOUND_WRAPPER)))
514 	for (j = 0; j < sp->nchans; j++)
515 	  if ((cp = ((chan_info *)(sp->chans[j]))))
516 	    (*func)(cp, value);
517     }
518 }
519 
520 
for_each_chan_with_float(void (* func)(chan_info * ncp,mus_float_t val),mus_float_t value)521 void for_each_chan_with_float(void (*func)(chan_info *ncp, mus_float_t val), mus_float_t value)
522 {
523   int i;
524   for (i = 0; i < ss->max_sounds; i++)
525     {
526       uint32_t j;
527       snd_info *sp;
528       chan_info *cp;
529       sp = ss->sounds[i];
530       if ((sp) && ((sp->inuse == SOUND_NORMAL) || (sp->inuse == SOUND_WRAPPER)))
531 	for (j = 0; j < sp->nchans; j++)
532 	  if ((cp = ((chan_info *)(sp->chans[j]))))
533 	    (*func)(cp, value);
534     }
535 }
536 
537 
for_each_chan(void (* func)(chan_info * ncp))538 void for_each_chan(void (*func)(chan_info *ncp))
539 {
540   int i;
541   for (i = 0; i < ss->max_sounds; i++)
542     {
543       uint32_t j;
544       snd_info *sp;
545       chan_info *cp;
546       sp = ss->sounds[i];
547       if ((sp) && ((sp->inuse == SOUND_NORMAL) || (sp->inuse == SOUND_WRAPPER)))
548 	for (j = 0; j < sp->nchans; j++)
549 	  if ((cp = ((chan_info *)(sp->chans[j]))))
550 	    (*func)(cp);
551     }
552 }
553 
554 
for_each_normal_chan_with_void(void (* func)(chan_info * ncp,void * ptr),void * userptr)555 void for_each_normal_chan_with_void(void (*func)(chan_info *ncp, void *ptr), void *userptr)
556 {
557   int i;
558   for (i = 0; i < ss->max_sounds; i++)
559     {
560       uint32_t j;
561       snd_info *sp;
562       chan_info *cp;
563       sp = ss->sounds[i];
564       if ((sp) && (sp->inuse == SOUND_NORMAL))
565 	for (j = 0; j < sp->nchans; j++)
566 	  if ((cp = ((chan_info *)(sp->chans[j]))))
567 	    (*func)(cp, userptr);
568     }
569 }
570 
571 
for_each_normal_chan_with_int(void (* func)(chan_info * ncp,int val),int value)572 void for_each_normal_chan_with_int(void (*func)(chan_info *ncp, int val), int value)
573 {
574   int i;
575   for (i = 0; i < ss->max_sounds; i++)
576     {
577       uint32_t j;
578       snd_info *sp;
579       chan_info *cp;
580       sp = ss->sounds[i];
581       if ((sp) && (sp->inuse == SOUND_NORMAL))
582 	for (j = 0; j < sp->nchans; j++)
583 	  if ((cp = ((chan_info *)(sp->chans[j]))))
584 	    (*func)(cp, value);
585     }
586 }
587 
588 
for_each_normal_chan_with_refint(void (* func)(chan_info * ncp,int * val),int * value)589 void for_each_normal_chan_with_refint(void (*func)(chan_info *ncp, int *val), int *value)
590 {
591   int i;
592   for (i = 0; i < ss->max_sounds; i++)
593     {
594       uint32_t j;
595       snd_info *sp;
596       chan_info *cp;
597       sp = ss->sounds[i];
598       if ((sp) && (sp->inuse == SOUND_NORMAL))
599 	for (j = 0; j < sp->nchans; j++)
600 	  if ((cp = ((chan_info *)(sp->chans[j]))))
601 	    (*func)(cp, value);
602     }
603 }
604 
605 
for_each_normal_chan(void (* func)(chan_info * ncp))606 void for_each_normal_chan(void (*func)(chan_info *ncp))
607 {
608   int i;
609   for (i = 0; i < ss->max_sounds; i++)
610     {
611       uint32_t j;
612       snd_info *sp;
613       chan_info *cp;
614       sp = ss->sounds[i];
615       if ((sp) && (sp->inuse == SOUND_NORMAL))
616 	for (j = 0; j < sp->nchans; j++)
617 	  if ((cp = ((chan_info *)(sp->chans[j]))))
618 	    (*func)(cp);
619     }
620 }
621 
622 
for_each_sound_chan_with_int(snd_info * sp,void (* func)(chan_info * ncp,int val1),int value)623 void for_each_sound_chan_with_int(snd_info *sp, void (*func)(chan_info *ncp, int val1), int value)
624 {
625   uint32_t j;
626   chan_info *cp;
627   for (j = 0; j < sp->nchans; j++)
628     if ((cp = sp->chans[j]))
629       (*func)(cp, value);
630 }
631 
632 
map_over_sound_chans(snd_info * sp,bool (* func)(chan_info * ncp))633 bool map_over_sound_chans(snd_info *sp, bool (*func)(chan_info *ncp))
634 {
635   uint32_t j;
636   bool val = false;
637   chan_info *cp;
638   for (j = 0; j < sp->nchans; j++)
639     if ((cp = sp->chans[j]))
640       {
641 	val = (*func)(cp);
642 	if (val) return(val);
643       }
644   return(val);
645 }
646 
647 
for_each_sound_chan(snd_info * sp,void (* func)(chan_info * ncp))648 void for_each_sound_chan(snd_info *sp, void (*func)(chan_info *ncp))
649 {
650   uint32_t j;
651   chan_info *cp;
652   for (j = 0; j < sp->nchans; j++)
653     if ((cp = sp->chans[j]))
654       (*func)(cp);
655 }
656 
657 
for_each_sound(void (* func)(snd_info * usp))658 void for_each_sound(void (*func)(snd_info *usp))
659 {
660   int i;
661   for (i = 0; i < ss->max_sounds; i++)
662     {
663       snd_info *sp;
664       sp = ss->sounds[i];
665       if ((sp) && (sp->inuse == SOUND_NORMAL))
666 	(*func)(sp);
667     }
668 }
669 
670 
for_each_sound_with_void(void (* func)(snd_info * usp,void * ptr),void * userptr)671 void for_each_sound_with_void(void (*func)(snd_info *usp, void *ptr), void *userptr)
672 {
673   int i;
674   for (i = 0; i < ss->max_sounds; i++)
675     {
676       snd_info *sp;
677       sp = ss->sounds[i];
678       if ((sp) && (sp->inuse == SOUND_NORMAL))
679 	(*func)(sp, userptr);
680     }
681 }
682 
683 
for_each_separate_chan(void (* func)(chan_info * ncp))684 void for_each_separate_chan(void (*func)(chan_info *ncp))
685 {
686   /* used only to lock/unlock panes */
687   int i;
688   for (i = 0; i < ss->max_sounds; i++)
689     {
690       snd_info *sp;
691       sp = ss->sounds[i];
692       if ((sp) && (sp->inuse == SOUND_NORMAL))
693 	{
694 	  if (sp->channel_style != CHANNELS_SEPARATE)
695 	    (*func)(sp->chans[0]);
696 	  else for_each_sound_chan(sp, func);
697 	}
698     }
699 }
700 
701 
snd_ok(snd_info * sp)702 bool snd_ok(snd_info *sp)
703 {
704   return((sp) &&
705 	 (sp->inuse != SOUND_IDLE) &&
706 	 (sp->active));
707 }
708 
709 
active_channels(virtual_channels_t count_virtual_channels)710 int active_channels(virtual_channels_t count_virtual_channels)
711 {
712   int chans = 0, i;
713   for (i = 0; i < ss->max_sounds; i++)
714     {
715       snd_info *sp;
716       sp = ss->sounds[i];
717       if (snd_ok(sp) &&
718 	  (sp->inuse != SOUND_WRAPPER))
719 	{
720 	  if ((count_virtual_channels == WITH_VIRTUAL_CHANNELS) ||
721 	      (sp->channel_style == CHANNELS_SEPARATE))
722 	    chans += sp->nchans;
723 	  else chans++;
724 	}
725     }
726   return(chans);
727 }
728 
729 
730 #define SOUNDS_ALLOC_SIZE 4
731 
find_free_sound_slot(int desired_chans)732 int find_free_sound_slot(int desired_chans)
733 {
734   int i, j;
735   snd_info *sp;
736   /* first try to find an unused slot that can accommodate desired_chans (to reduce Widget creation) */
737   if (ss->reloading_updated_file > 0)
738     {
739       /* snd_update should change the underlying slot only when it has to (user increased chans) */
740       sp = ss->sounds[ss->reloading_updated_file - 1];
741       if ((!sp) ||
742 	  ((sp->inuse == SOUND_IDLE) && (sp->allocated_chans >= desired_chans)))
743 	return(ss->reloading_updated_file - 1);
744     }
745   for (i = 0; i < ss->max_sounds; i++)
746     {
747       sp = ss->sounds[i];
748       if ((sp) && (sp->inuse == SOUND_IDLE) && (sp->allocated_chans == desired_chans)) return(i);
749     }
750   for (i = 0; i < ss->max_sounds; i++)
751     {
752       sp = ss->sounds[i];
753       if ((sp) && (sp->inuse == SOUND_IDLE) && (sp->allocated_chans > desired_chans)) return(i);
754     }
755   for (i = 0; i < ss->max_sounds; i++)
756     {
757       sp = ss->sounds[i];
758       if (!sp) return(i);
759       if (sp->inuse == SOUND_IDLE) return(i);
760     }
761   j = ss->max_sounds;
762   ss->max_sounds += SOUNDS_ALLOC_SIZE;
763   ss->sounds = (snd_info **)realloc(ss->sounds, ss->max_sounds * sizeof(snd_info *));
764   for (i = j; i < ss->max_sounds; i++) ss->sounds[i] = NULL;
765   return(j);
766 }
767 
768 
find_free_sound_slot_for_channel_display(void)769 int find_free_sound_slot_for_channel_display(void)
770 {
771   int i, j;
772   for (i = 0; i < ss->max_sounds; i++)
773     if (!ss->sounds[i]) return(i);
774   j = ss->max_sounds;
775   ss->max_sounds += SOUNDS_ALLOC_SIZE;
776   ss->sounds = (snd_info **)realloc(ss->sounds, ss->max_sounds * sizeof(snd_info *));
777   for (i = j; i < ss->max_sounds; i++) ss->sounds[i] = NULL;
778   return(j);
779 }
780 
781 
any_active_sound(void)782 static snd_info *any_active_sound(void)
783 {
784   int i;
785   for (i = 0; i < ss->max_sounds; i++)
786     {
787       snd_info *sp;
788       sp = ss->sounds[i];
789       if ((sp) && (sp->inuse == SOUND_NORMAL))
790 	return(sp);
791     }
792   return(NULL);
793 }
794 
795 
selected_sound(void)796 snd_info *selected_sound(void)
797 {
798   if ((ss->selected_sound != NO_SELECTION) &&
799       (snd_ok(ss->sounds[ss->selected_sound])))
800     return(ss->sounds[ss->selected_sound]);
801   ss->selected_sound = NO_SELECTION;
802   return(NULL);
803 }
804 
805 
any_selected_sound(void)806 snd_info *any_selected_sound(void)
807 {
808   snd_info *sp;
809   sp = selected_sound();
810   if (!sp) sp = any_active_sound();
811   return(sp);
812 }
813 
814 
any_selected_channel(snd_info * sp)815 chan_info *any_selected_channel(snd_info *sp)
816 {
817   int chan = 0;
818   if (sp->selected_channel != NO_SELECTION)
819     chan = sp->selected_channel;
820   if ((sp->chans[chan]) &&
821       (sp->chans[chan]->active > CHANNEL_INITIALIZED))
822     return(sp->chans[chan]);
823   return(NULL);
824 }
825 
826 
selected_channel(void)827 chan_info *selected_channel(void)
828 {
829   if (ss->selected_sound != NO_SELECTION)
830     {
831       snd_info *sp;
832       sp = ss->sounds[ss->selected_sound];
833       if ((sp->inuse == SOUND_NORMAL) && (sp->selected_channel != NO_SELECTION))
834 	return(sp->chans[sp->selected_channel]);
835     }
836   return(NULL);
837 }
838 
839 
840 static Xen select_sound_hook;
841 static Xen select_channel_hook;
842 static int current_selectpos = 0;
843 
select_sound(snd_info * sp)844 static void select_sound(snd_info *sp)
845 {
846   if ((!sp) || (sp->inuse != SOUND_NORMAL)) return;
847 
848   if (Xen_hook_has_list(select_sound_hook))
849     run_hook(select_sound_hook,
850 	     Xen_list_1(C_int_to_Xen_sound(sp->index)),
851 	     S_select_sound_hook);
852 
853   if (ss->selected_sound != sp->index)
854     {
855       reflect_sound_selection(sp);
856       ss->selected_sound = sp->index;
857       new_active_channel_alert();
858       reflect_save_as_sound_selection(sp->short_filename);
859     }
860   sp->selectpos = current_selectpos++;
861 
862   if (Xen_hook_has_list(ss->effects_hook))
863     run_hook(ss->effects_hook, Xen_empty_list, S_effects_hook);
864 }
865 
866 
color_selected_channel(snd_info * sp)867 chan_info *color_selected_channel(snd_info *sp)
868 {
869   chan_info *ncp;
870   ncp = sp->chans[sp->selected_channel];
871   recolor_graph(ncp, true);
872   ncp->selected = true;
873   update_graph(ncp); /* update any indication of change in selected channel (channel id for example) */
874   return(ncp);
875 }
876 
877 
select_channel(snd_info * sp,int chan)878 void select_channel(snd_info *sp, int chan)
879 {
880   chan_info *cp;
881 
882   if ((!sp) || (sp->inuse != SOUND_NORMAL)) return;
883   cp = selected_channel();
884   if (cp != sp->chans[chan])
885     {
886       chan_info *ncp;
887       sp->selected_channel = chan;
888       select_sound(sp);
889       if (cp)
890 	{
891 	  recolor_graph(cp, false);
892 	  cp->selected = false;
893 	  if (sp != cp->sound) cp->sound->selected_channel = NO_SELECTION;
894 	  update_graph(cp);
895 	}
896       if (Xen_hook_has_list(select_channel_hook))
897 	run_hook(select_channel_hook,
898 		 Xen_list_2(C_int_to_Xen_sound(sp->index),
899 			    C_int_to_Xen_integer(chan)),
900 		 S_select_channel_hook);
901       ncp = color_selected_channel(sp);
902       goto_graph(ncp);
903     }
904 }
905 
906 
current_channel(void)907 chan_info *current_channel(void)
908 {
909   snd_info *sp = NULL;
910   if (ss->selected_sound != NO_SELECTION)
911     sp = ss->sounds[ss->selected_sound];
912   else sp = any_active_sound();
913   if (sp) return(any_selected_channel(sp));
914   return(NULL);
915 }
916 
917 
free_sync_info(sync_info * si)918 sync_info *free_sync_info(sync_info *si)
919 {
920   if (si)
921     {
922       if (si->begs) free(si->begs);
923       si->begs = NULL;
924       if (si->cps) free(si->cps);
925       si->cps = NULL;
926       free(si);
927     }
928   return(NULL);
929 }
930 
931 
syncd_channels(int sync)932 int syncd_channels(int sync)
933 {
934   if (sync != 0)
935     {
936       int i, chans = 0;
937       snd_info *sp;
938       for (i = 0; i < ss->max_sounds; i++)
939 	{
940 	  sp = ss->sounds[i];
941 	  if ((sp) &&
942 	      (sp->inuse == SOUND_NORMAL) &&
943 	      (sp->sync == sync))
944 	    chans += sp->nchans;
945 	}
946       return(chans);
947     }
948   return(0);
949 }
950 
951 
snd_sync(int sync)952 sync_info *snd_sync(int sync)
953 {
954   int chans;
955   snd_info *sp;
956   chans = syncd_channels(sync);
957   if (chans > 0)
958     {
959       int i, j;
960       sync_info *si;
961       si = (sync_info *)calloc(1, sizeof(sync_info));
962       si->begs = (mus_long_t *)calloc(chans, sizeof(mus_long_t));
963       si->cps = (chan_info **)calloc(chans, sizeof(chan_info *));
964       si->chans = chans;
965       for (i = 0, j = 0; i < ss->max_sounds; i++)
966 	{
967 	  sp = ss->sounds[i];
968 	  if ((sp) &&
969 	      (sp->inuse == SOUND_NORMAL) &&
970 	      (sp->sync == sync))
971 	    {
972 	      uint32_t k;
973 	      for (k = 0; k < sp->nchans; k++, j++)
974 		si->cps[j] = sp->chans[k];
975 	    }
976 	}
977       return(si);
978     }
979   return(NULL);
980 }
981 
982 
make_simple_sync(chan_info * cp,mus_long_t beg)983 sync_info *make_simple_sync(chan_info *cp, mus_long_t beg)
984 {
985   sync_info *si;
986   si = (sync_info *)calloc(1, sizeof(sync_info));
987   si->chans = 1;
988   si->cps = (chan_info **)calloc(1, sizeof(chan_info *));
989   si->cps[0] = cp;
990   si->begs = (mus_long_t *)calloc(1, sizeof(mus_long_t));
991   si->begs[0] = beg;
992   return(si);
993 }
994 
995 
sync_to_chan(chan_info * cp)996 sync_info *sync_to_chan(chan_info *cp)
997 {
998   snd_info *sp;
999   sp = cp->sound;
1000   if (sp->sync != 0)
1001     return(snd_sync(sp->sync));
1002   return(make_simple_sync(cp, 0));
1003 }
1004 
1005 
find_sound(const char * name,int nth)1006 snd_info *find_sound(const char *name, int nth)
1007 {
1008   char *sname;
1009   int i, which = 0;
1010   if (!name) return(NULL);
1011   sname = filename_without_directory(name);
1012   for (i = 0; i < ss->max_sounds; i++)
1013     {
1014       snd_info *sp;
1015       sp = ss->sounds[i];
1016       if ((sp) && (sp->inuse == SOUND_NORMAL))
1017 	if ((mus_strcmp(name, sp->short_filename)) ||
1018 	    (mus_strcmp(name, sp->filename)) ||
1019 	    (mus_strcmp(sname, sp->short_filename)))
1020 	  {
1021 	    if (which == nth) return(sp);
1022 	    which++;
1023 	  }
1024     }
1025   return(NULL);
1026 }
1027 
1028 
g_init_data(void)1029 void g_init_data(void)
1030 {
1031   #define H_select_sound_hook S_select_sound_hook " (snd): called whenever a sound is selected."
1032 
1033   #define H_select_channel_hook S_select_channel_hook " (snd chn): called whenever a channel is selected. \
1034 Its arguments are the sound index and the channel number."
1035 
1036   select_sound_hook =   Xen_define_hook(S_select_sound_hook,   "(make-hook 'snd)",      1, H_select_sound_hook);
1037   select_channel_hook = Xen_define_hook(S_select_channel_hook, "(make-hook 'snd 'chn)", 2, H_select_channel_hook);
1038 }
1039 
1040