1 #include "snd.h"
2 #include "sndlib-strings.h"
3 #include "clm2xen.h"
4
5
6 #define REGION_FILE 1
7 #define REGION_DEFERRED 0
8
9 /* region data can be stored either in a temp file that is deleted when the region is deleted (hence must be copied upon insert or mix)
10 * or as a descriptor of current chan/beg/num/edpos locs. The descriptor form is used until some use is made of the data
11 * that requires a file anyway (e.g. mixing), or if the data the descriptor depends on is about to be flushed (e.g. the
12 * underlying edit list is about to be cleared, or the file is being closed, etc).
13 */
14
15
16 #define CLEAR_REGION_DATA 0
17 #define COMPLETE_DELETION 1
18
19 static int region_id_ctr = 0;
20
21 typedef struct {
22 int chans;
23 mus_long_t len;
24 chan_info **cps;
25 int *edpos;
26 } deferred_region;
27
28
free_deferred_region(deferred_region * dr)29 static deferred_region *free_deferred_region(deferred_region *dr)
30 {
31 if (dr)
32 {
33 if (dr->cps) free(dr->cps);
34 if (dr->edpos) free(dr->edpos);
35 free(dr);
36 }
37 return(NULL);
38 }
39
40
41 typedef struct region {
42 int chans;
43 mus_long_t framples;
44 int srate; /* for file save (i.e. region->file) */
45 int header_type; /* for file save */
46 snd_info *rsp;
47 char *name, *start, *end; /* for region browser */
48 char *filename; /* if region data is stored in a temp file */
49 int use_temp_file; /* REGION_FILE = in temp file 'filename', REGION_DEFERRED = in 'dr' */
50 mus_float_t maxamp;
51 mus_long_t maxamp_position;
52 snd_info *editor_copy;
53 char *editor_name;
54 int id;
55 deferred_region *dr; /* REGION_DEFERRED descriptor */
56 peak_env_info **peak_envs;
57 mus_long_t *begs, *ends;
58 } region;
59
60
61 static void deferred_region_to_temp_file(region *r);
62
free_region(region * r,int complete)63 static void free_region(region *r, int complete)
64 {
65 /* if not complete, just clear out old data (edited region being saved) */
66 if (r)
67 {
68 if (complete == COMPLETE_DELETION)
69 {
70 if (r->editor_copy)
71 {
72 snd_info *sp;
73 sp = r->editor_copy;
74 sp->edited_region = NULL;
75 r->editor_copy = NULL;
76 }
77 if (r->name) free(r->name);
78 if (r->start) free(r->start);
79 if (r->end) free(r->end);
80 if (r->begs) free(r->begs);
81 if (r->ends) free(r->ends);
82 if (r->peak_envs)
83 {
84 int i;
85 for (i = 0; i < r->chans; i++)
86 if (r->peak_envs[i])
87 r->peak_envs[i] = free_peak_env_info(r->peak_envs[i]);
88 free(r->peak_envs);
89 r->peak_envs = NULL;
90 }
91 }
92 if (r->use_temp_file == REGION_FILE) /* we can delete this temp file because all references copy first */
93 {
94 if (r->filename)
95 {
96 snd_remove(r->filename, REMOVE_FROM_CACHE);
97 free(r->filename);
98 }
99 r->filename = NULL;
100 }
101 if (r->use_temp_file == REGION_DEFERRED)
102 r->dr = free_deferred_region(r->dr);
103 if (r->rsp)
104 {
105 if ((r->rsp->chans) &&
106 (r->rsp->chans[0]->edits))
107 r->rsp->chans[0]->edits[0]->peak_env = NULL;
108 r->rsp = completely_free_snd_info(r->rsp);
109 }
110 if (complete == COMPLETE_DELETION) free(r);
111 }
112 }
113
114
115 static region **regions = NULL;
116 static int regions_size = 0, regions_allocated_size = 0;
117
allocate_regions(int numreg)118 void allocate_regions(int numreg)
119 {
120 int i;
121 if (numreg > regions_allocated_size)
122 {
123 if (regions)
124 {
125 regions = (region **)realloc(regions, numreg * sizeof(region *));
126 for (i = regions_allocated_size; i < numreg; i++) regions[i] = NULL;
127 }
128 else regions = (region **)calloc(numreg, sizeof(region *));
129 regions_allocated_size = numreg;
130 }
131 if (regions_size > numreg)
132 {
133 for (i = numreg; i < regions_size; i++)
134 if (regions[i])
135 {
136 free_region(regions[i], COMPLETE_DELETION);
137 regions[i] = NULL;
138 }
139 if (region_browser_is_active()) update_region_browser(true);
140 }
141 regions_size = numreg;
142 }
143
144
set_max_regions(int n)145 static void set_max_regions(int n)
146 {
147 if (n >= 0)
148 {
149 allocate_regions(n);
150 allocate_region_rows(n);
151 in_set_max_regions(n);
152 }
153 }
154
155
region_id_to_list_position(int id)156 int region_id_to_list_position(int id)
157 {
158 int i;
159 if ((id >= 0) && (id < region_id_ctr))
160 for (i = 0; i < regions_size; i++)
161 if ((regions[i]) &&
162 (regions[i]->id == id))
163 return(i);
164 return(INVALID_REGION);
165 }
166
167
region_list_position_to_id(int n)168 int region_list_position_to_id(int n)
169 {
170 if ((n >= 0) &&
171 (n < regions_size) &&
172 (regions[n]))
173 return(regions[n]->id);
174 return(INVALID_REGION);
175 }
176
177
id_to_region(int id)178 static region *id_to_region(int id)
179 {
180 int i;
181 if ((id >= 0) && (id < region_id_ctr))
182 for (i = 0; i < regions_size; i++)
183 if ((regions[i]) &&
184 (regions[i]->id == id))
185 return(regions[i]);
186 return(NULL);
187 }
188
189
region_ok(int id)190 bool region_ok(int id)
191 {
192 return((bool)id_to_region(id));
193 }
194
195
region_len(int n)196 mus_long_t region_len(int n)
197 {
198 region *r;
199 r = id_to_region(n);
200 if (r)
201 return(r->framples);
202 return(0);
203 }
204
205
region_chans(int n)206 int region_chans(int n)
207 {
208 region *r;
209 r = id_to_region(n);
210 if (r)
211 return(r->chans);
212 return(0);
213 }
214
215
region_srate(int n)216 int region_srate(int n)
217 {
218 region *r;
219 r = id_to_region(n);
220 if (r)
221 return(r->srate);
222 return(0);
223 }
224
225
region_file_name(int n)226 const char *region_file_name(int n)
227 {
228 region *r;
229 r = id_to_region(n);
230 if (r)
231 return(r->name);
232 return(NULL);
233 }
234
235
get_region_maxamp(region * r)236 static void get_region_maxamp(region *r)
237 {
238 /* it exists as r->filename, so just use sndlib... */
239 mus_float_t *vals;
240 mus_long_t *times;
241 int i;
242 mus_long_t maxpos;
243 mus_float_t maxsamp;
244 vals = (mus_float_t *)calloc(r->chans, sizeof(mus_float_t));
245 times = (mus_long_t *)calloc(r->chans, sizeof(mus_long_t));
246 mus_sound_maxamps(r->filename, r->chans, vals, times);
247 maxpos = times[0];
248 maxsamp = vals[0];
249 for (i = 1; i < r->chans; i++)
250 if (vals[i] > maxsamp)
251 {
252 maxsamp = vals[i];
253 maxpos = times[i];
254 }
255 free(vals);
256 free(times);
257 r->maxamp = maxsamp;
258 r->maxamp_position = maxpos;
259 }
260
261
region_maxamp(int n)262 mus_float_t region_maxamp(int n)
263 {
264 region *r;
265 r = id_to_region(n);
266 if (r)
267 {
268 if (r->maxamp < 0.0)
269 {
270 if (r->use_temp_file == REGION_DEFERRED)
271 deferred_region_to_temp_file(r);
272 get_region_maxamp(r);
273 }
274 return(r->maxamp);
275 }
276 return(0.0);
277 }
278
279
region_maxamp_position(int n)280 static mus_long_t region_maxamp_position(int n)
281 {
282 region *r;
283 r = id_to_region(n);
284 if (r)
285 {
286 if (r->maxamp < 0.0)
287 {
288 if (r->use_temp_file == REGION_DEFERRED)
289 deferred_region_to_temp_file(r);
290 get_region_maxamp(r);
291 }
292 return(r->maxamp_position);
293 }
294 return(-1);
295 }
296
297
region_sample(int reg,int chn,mus_long_t samp)298 static mus_float_t region_sample(int reg, int chn, mus_long_t samp)
299 {
300 region *r;
301 r = id_to_region(reg);
302 if (r)
303 {
304 if ((samp < r->framples) && (chn < r->chans))
305 {
306 snd_fd *sf;
307 mus_float_t val;
308 deferred_region *drp;
309 switch (r->use_temp_file)
310 {
311 case REGION_FILE:
312 sf = init_region_read(samp, reg, chn, READ_FORWARD);
313 val = read_sample(sf);
314 free_snd_fd(sf);
315 return(val);
316
317 case REGION_DEFERRED:
318 drp = r->dr;
319 return(chn_sample(samp + r->begs[chn], drp->cps[chn], drp->edpos[chn]));
320 }
321 }
322 }
323 return(0.0);
324 }
325
326
region_current_location(snd_fd * fd)327 mus_long_t region_current_location(snd_fd *fd)
328 {
329 region *r;
330 r = id_to_region(fd->region);
331 switch (r->use_temp_file)
332 {
333 case REGION_FILE:
334 return(current_location(fd));
335 case REGION_DEFERRED:
336 return(current_location(fd) - r->begs[0]);
337 }
338 return(-1);
339 }
340
341
region_samples(int reg,int chn,mus_long_t beg,mus_long_t num,mus_float_t * data)342 static void region_samples(int reg, int chn, mus_long_t beg, mus_long_t num, mus_float_t *data)
343 {
344 region *r;
345 r = id_to_region(reg);
346 if (r)
347 {
348 if ((beg < r->framples) && (chn < r->chans))
349 {
350 snd_fd *sf;
351 deferred_region *drp;
352 switch (r->use_temp_file)
353 {
354 case REGION_FILE:
355 sf = init_region_read(beg, reg, chn, READ_FORWARD);
356 samples_to_vct_with_reader(num, data, sf);
357 free_snd_fd(sf);
358 break;
359
360 case REGION_DEFERRED:
361 drp = r->dr;
362 sf = init_sample_read_any_with_bufsize(beg + r->begs[chn], drp->cps[chn], READ_FORWARD, drp->edpos[chn], num);
363 samples_to_vct_with_reader(num, data, sf);
364 free_snd_fd(sf);
365 break;
366 }
367 }
368 }
369 }
370
371
first_region_active(void)372 static int first_region_active(void)
373 {
374 int i;
375 for (i = 0; i < regions_size; i++)
376 if (regions[i])
377 return(i);
378 return(NO_REGIONS);
379 }
380
381
check_regions(void)382 static int check_regions(void)
383 {
384 int act;
385 act = first_region_active();
386 if (act == NO_REGIONS)
387 reflect_no_regions_in_region_browser();
388 return(act);
389 }
390
391
make_region_readable(region * r)392 static void make_region_readable(region *r)
393 {
394 snd_info *regsp;
395 file_info *hdr;
396 int i;
397
398 if (r->use_temp_file == REGION_DEFERRED)
399 deferred_region_to_temp_file(r);
400 if (r->rsp) return;
401
402 regsp = make_basic_snd_info(r->chans);
403 regsp->nchans = r->chans;
404 regsp->hdr = (file_info *)calloc(1, sizeof(file_info));
405 regsp->inuse = SOUND_READER;
406
407 hdr = regsp->hdr;
408 hdr->samples = r->framples * r->chans;
409 hdr->srate = r->srate;
410 hdr->chans = r->chans;
411 hdr->comment = NULL;
412
413 for (i = 0; i < r->chans; i++)
414 {
415 hdr = make_file_info(r->filename, FILE_READ_ONLY, FILE_NOT_SELECTED);
416 if (hdr)
417 {
418 snd_io *io;
419 int fd;
420 chan_info *cp;
421
422 cp = make_chan_info(NULL, i, regsp);
423 cp->editable = false;
424 regsp->chans[i] = cp;
425 add_channel_data_1(cp, r->srate, r->framples, WITHOUT_GRAPH);
426 cp->hookable = WITHOUT_HOOK;
427
428 fd = snd_open_read(r->filename);
429 snd_file_open_descriptors(fd,
430 r->filename,
431 hdr->sample_type,
432 hdr->data_location,
433 hdr->chans,
434 hdr->type);
435 io = make_file_state(fd, hdr, i, 0, FILE_BUFFER_SIZE);
436 cp->sounds[0] = make_snd_data_file(r->filename, io, hdr, DONT_DELETE_ME, cp->edit_ctr, i); /* don't auto-delete! */
437 }
438 else
439 {
440 Xen_error(Xen_make_error_type("IO-error"),
441 Xen_list_3(C_string_to_Xen_string("can't read region file ~S, ~A"),
442 C_string_to_Xen_string(r->filename),
443 C_string_to_Xen_string(snd_open_strerror())));
444 }
445 }
446 r->rsp = regsp;
447 }
448
449
fixup_region_data(chan_info * cp,int chan,int pos)450 file_info *fixup_region_data(chan_info *cp, int chan, int pos)
451 {
452 /* for region browser labels */
453 if ((pos >= 0) &&
454 (pos < regions_size) &&
455 (regions[pos]))
456 {
457 region *r;
458 r = regions[pos];
459 if (chan < r->chans)
460 {
461 snd_info *nsp;
462 chan_info *ncp;
463
464 make_region_readable(r);
465 nsp = r->rsp;
466 ncp = nsp->chans[chan];
467
468 cp->sounds = ncp->sounds;
469 cp->sound_size = ncp->sound_size;
470 cp->edits = ncp->edits; /* ?? is this safe ?? */
471 cp->edit_size = ncp->edit_size;
472 cp->edit_ctr = ncp->edit_ctr;
473 cp->edits[0]->samples = ncp->edits[0]->samples;
474 cp->axis = ncp->axis;
475
476 /* cp here is actually region sound chan 0 */
477 if ((r->peak_envs) && (r->peak_envs[chan]))
478 cp->edits[0]->peak_env = r->peak_envs[chan];
479 else
480 {
481 if (cp->edits[0]->peak_env)
482 cp->edits[0]->peak_env = NULL;
483 }
484
485 initialize_scrollbars(cp);
486 return(nsp->hdr);
487 }
488 }
489 return(NULL);
490 }
491
492
for_each_region_chan_with_refint(void (* func)(chan_info * ncp,int * val),int * value)493 void for_each_region_chan_with_refint(void (*func)(chan_info *ncp, int *val), int *value)
494 {
495 /* used only in snd-io.c to remove dangling temp files (probably can't actually happen) */
496 int i;
497 for (i = 0; i < regions_size; i++)
498 {
499 int chn;
500 region *r;
501 r = regions[i];
502 if ((r) && (r->rsp) && (r->use_temp_file == REGION_FILE))
503 for (chn = 0; chn < r->chans; chn++)
504 {
505 chan_info *cp;
506 cp = r->rsp->chans[chn];
507 (*func)(cp, value);
508 }
509 }
510 }
511
512
region_report(void)513 region_state *region_report(void)
514 {
515 region_state *rs;
516 int i, len, size;
517
518 rs = (region_state *)calloc(1, sizeof(region_state));
519 len = regions_size;
520 for (i = 0; i < regions_size; i++)
521 if (!(regions[i]))
522 {
523 len = i;
524 break;
525 }
526 rs->len = len;
527 if (len == 0) return(rs);
528 size = len * sizeof(char *);
529 rs->name = (char **)calloc(size, 1);
530 for (i = 0; i < len; i++)
531 {
532 region *r;
533 char *reg_buf;
534 r = regions[i];
535 reg_buf = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char));
536 snprintf(reg_buf, LABEL_BUFFER_SIZE, "%d: %s (%s:%s)", r->id, r->name, r->start, r->end);
537 rs->name[i] = reg_buf;
538 }
539 return(rs);
540 }
541
542
region_description(int rg)543 char *region_description(int rg)
544 {
545 region *r;
546 r = id_to_region(rg);
547 if (r)
548 return(mus_format("region data from %s (%s : %s)", r->name, r->start, r->end));
549 return(NULL);
550 }
551
552
free_region_state(region_state * r)553 void free_region_state(region_state *r)
554 {
555 if (r)
556 {
557 int i;
558 for (i = 0; i < r->len; i++)
559 if (r->name[i])
560 free(r->name[i]);
561 if (r->name) free(r->name);
562 free(r);
563 }
564 }
565
566
remove_region_from_list(int pos)567 int remove_region_from_list(int pos) /* region browser */
568 {
569 int i, id;
570 id = region_list_position_to_id(pos);
571 if (id == INVALID_REGION) return(INVALID_REGION);
572
573 stop_playing_region(id, PLAY_CLOSE);
574
575 free_region(id_to_region(id), COMPLETE_DELETION);
576 for (i = pos; i < regions_size - 1; i++)
577 regions[i] = regions[i + 1];
578 regions[regions_size - 1] = NULL;
579
580 return(check_regions());
581 }
582
583
add_to_region_list(region * r)584 static void add_to_region_list(region *r)
585 {
586 int i, okr = -1;
587 for (i = max_regions(ss) - 1; i >= 0; i--)
588 {
589 if (!(regions[i]))
590 {
591 okr = i;
592 break;
593 }
594 }
595 if (okr == -1)
596 okr = max_regions(ss) - 1;
597 if (regions[okr])
598 {
599 stop_playing_region(regions[okr]->id, PLAY_CLOSE);
600 free_region(regions[okr], COMPLETE_DELETION);
601 }
602 for (i = okr; i > 0; i--)
603 regions[i] = regions[i - 1];
604 regions[0] = r;
605 if (!r) check_regions();
606 }
607
608
609 #define NOT_EDITABLE -2
610
paste_region_1(int n,chan_info * cp,bool add,mus_long_t beg,io_error_t * err,int start_chan,int * out_chans)611 static int paste_region_1(int n, chan_info *cp, bool add, mus_long_t beg, io_error_t *err, int start_chan, int *out_chans)
612 {
613 region *r;
614 char *origin = NULL;
615 int id = -1;
616 io_error_t io_err;
617 sync_info *si = NULL;
618
619 r = id_to_region(n);
620 if ((!r) ||
621 (r->framples == 0))
622 return(INVALID_REGION);
623
624 if (!(is_editable(cp)))
625 {
626 (*err) = IO_EDIT_HOOK_CANCELLATION;
627 return(NOT_EDITABLE);
628 }
629
630 if (r->use_temp_file == REGION_DEFERRED)
631 deferred_region_to_temp_file(r);
632
633 si = sync_to_chan(cp);
634 (*out_chans) = si->chans;
635
636 if (add)
637 {
638 /* unfortunately we need to copy here since the region may fall off the region stack while we're still using the mix */
639 char *newname;
640 newname = shorter_tempnam(temp_dir(ss), "snd_");
641 io_err = copy_file(r->filename, newname);
642 if (io_err != IO_NO_ERROR)
643 {
644 (*err) = io_err;
645 return(INVALID_REGION);
646 }
647 else
648 {
649 #if HAVE_FORTH
650 origin = mus_format("%d %s %" print_mus_long " %s drop", n, S_integer_to_region, beg, S_mix_region);
651 #endif
652 #if HAVE_RUBY
653 origin = mus_format("%s(%s(%d), %" print_mus_long, to_proc_name(S_mix_region), to_proc_name(S_integer_to_region), n, beg);
654 #endif
655 #if HAVE_SCHEME || (!HAVE_EXTENSION_LANGUAGE)
656 origin = mus_format("%s (%s %d) %" print_mus_long, S_mix_region, S_integer_to_region, n, beg);
657 #endif
658 if (si->chans > 1)
659 remember_temp(newname, si->chans);
660
661 id = mix_file(beg, r->framples, si->chans, si->cps, newname,
662 (si->chans > 1) ? MULTICHANNEL_DELETION : DELETE_ME,
663 origin, with_mix_tags(ss), start_chan);
664 free(origin);
665 }
666 if (newname) free(newname);
667 }
668 else
669 {
670 int i;
671 char *tempfile = NULL;
672 if (r->use_temp_file == REGION_FILE)
673 {
674 tempfile = snd_tempnam();
675 io_err = copy_file(r->filename, tempfile);
676 if (io_err != IO_NO_ERROR)
677 {
678 if (si) free_sync_info(si);
679 (*err) = io_err;
680 return(INVALID_REGION);
681 }
682 else
683 if (r->chans > 1)
684 remember_temp(tempfile, r->chans);
685 }
686
687 #if HAVE_FORTH
688 origin = mus_format("%d %s %" print_mus_long " %s drop", n, S_integer_to_region, beg, S_insert_region);
689 #endif
690 #if HAVE_RUBY
691 origin = mus_format("%s(%s(%d), %" print_mus_long, to_proc_name(S_insert_region), to_proc_name(S_integer_to_region), n, beg);
692 #endif
693 #if HAVE_SCHEME || (!HAVE_EXTENSION_LANGUAGE)
694 origin = mus_format("%s (%s %d) %" print_mus_long, S_insert_region, S_integer_to_region, n, beg);
695 #endif
696
697 for (i = 0; ((i < r->chans) && (i < si->chans)); i++)
698 {
699 chan_info *ncp;
700 ncp = si->cps[i]; /* currently syncd chan that we might paste to */
701 if (file_insert_samples(beg, r->framples, tempfile, ncp, i,
702 (r->chans > 1) ? MULTICHANNEL_DELETION : DELETE_ME,
703 origin, ncp->edit_ctr))
704 update_graph(si->cps[i]);
705 }
706 free(origin);
707 if ((r->use_temp_file == REGION_FILE) && (tempfile)) free(tempfile);
708 }
709 if (si) free_sync_info(si);
710 return(id);
711 }
712
713
paste_region_2(int n,chan_info * cp,bool add,mus_long_t beg)714 static io_error_t paste_region_2(int n, chan_info *cp, bool add, mus_long_t beg)
715 {
716 io_error_t err = IO_NO_ERROR;
717 int chans = 0;
718 paste_region_1(n, cp, add, beg, &err, 0, &chans);
719 return(err);
720 }
721
722
paste_region(int n,chan_info * cp)723 io_error_t paste_region(int n, chan_info *cp)
724 {
725 return(paste_region_2(n, cp, false, cursor_sample(cp)));
726 }
727
728
add_region(int n,chan_info * cp)729 io_error_t add_region(int n, chan_info *cp)
730 {
731 return(paste_region_2(n, cp, true, cursor_sample(cp)));
732 }
733
734
define_region(sync_info * si,mus_long_t * ends)735 int define_region(sync_info *si, mus_long_t *ends)
736 {
737 /* now look at all sync'd channels, collect them into the current region */
738 /* we created the necessary pointers in create_selection above */
739 int i;
740 mus_long_t len;
741 chan_info *cp0;
742 snd_info *sp0;
743 region *r;
744 deferred_region *drp;
745
746 len = 0;
747 for (i = 0; i < si->chans; i++)
748 if (len < (ends[i] - si->begs[i]))
749 len = ends[i] - si->begs[i];
750 len += 1;
751 if (len <= 0) return(INVALID_REGION);
752
753 cp0 = si->cps[0];
754 sp0 = cp0->sound;
755
756 r = (region *)calloc(1, sizeof(region));
757 r->id = region_id_ctr++;
758
759 if (regions[0])
760 add_to_region_list(r);
761 else regions[0] = r;
762
763 r->header_type = (sp0->hdr)->type;
764 r->srate = snd_srate(sp0);
765 r->maxamp = -1.0;
766 r->maxamp_position = -1;
767 r->editor_copy = NULL;
768 r->name = mus_strdup(sp0->short_filename);
769 r->chans = si->chans;
770 r->framples = len;
771 r->start = prettyf((double)(si->begs[0]) / (double)(r->srate), 2);
772 r->end = prettyf((double)(ends[0]) / (double)(r->srate), 2);
773 r->use_temp_file = REGION_DEFERRED;
774 r->begs = (mus_long_t *)calloc(r->chans, sizeof(mus_long_t));
775 r->ends = (mus_long_t *)calloc(r->chans, sizeof(mus_long_t));
776
777 ss->deferred_regions++;
778 r->dr = (deferred_region *)calloc(1, sizeof(deferred_region));
779 drp = r->dr;
780 drp->chans = si->chans;
781 drp->cps = (chan_info **)calloc(drp->chans, sizeof(chan_info *));
782 drp->edpos = (int *)calloc(drp->chans, sizeof(int));
783 drp->len = len;
784
785 for (i = 0; i < drp->chans; i++)
786 {
787 drp->cps[i] = si->cps[i];
788 r->begs[i] = si->begs[i];
789 r->ends[i] = ends[i] - si->begs[i];
790 drp->edpos[i] = drp->cps[i]->edit_ctr;
791 if (r->ends[i] > PEAK_ENV_CUTOFF)
792 {
793 peak_env_info *ep;
794 ep = drp->cps[i]->edits[drp->edpos[i]]->peak_env;
795 if ((ep) && (ep->completed))
796 {
797 if (!r->peak_envs)
798 r->peak_envs = (peak_env_info **)calloc(r->chans, sizeof(peak_env_info *));
799 r->peak_envs[i] = peak_env_section(drp->cps[i], r->begs[i], r->ends[i] + 1, drp->edpos[i]);
800 }
801 }
802 }
803
804 reflect_regions_in_region_browser();
805 if (region_browser_is_active()) update_region_browser(true);
806 return(r->id);
807 }
808
809
deferred_region_to_temp_file(region * r)810 static void deferred_region_to_temp_file(region *r)
811 {
812 int i, datumb = 0;
813 bool copy_ok;
814 mus_long_t alloc_len, len = 0;
815 snd_fd **sfs = NULL;
816 snd_info *sp0;
817 deferred_region *drp = NULL;
818 mus_float_t **data = NULL;
819
820 ss->deferred_regions--;
821 drp = r->dr;
822 len = drp->len;
823 r->use_temp_file = REGION_FILE;
824 r->filename = snd_tempnam();
825 sp0 = drp->cps[0]->sound;
826
827 copy_ok = ((mus_header_writable(MUS_NEXT, sp0->hdr->sample_type)) &&
828 (r->chans == (int)sp0->nchans) &&
829 (r->peak_envs) &&
830 ((drp->len - 1) == r->ends[0]));
831 if (copy_ok)
832 for (i = 0; i < r->chans; i++)
833 if ((drp->edpos[i] != 0) ||
834 (drp->cps[i]->sound != sp0) ||
835 (r->begs[i] != r->begs[0]) ||
836 (r->ends[i] != (drp->len - 1)) ||
837 (!r->peak_envs[i]))
838 {
839 copy_ok = false;
840 break;
841 }
842
843 if (copy_ok)
844 {
845 /* write next header with correct len
846 * seek loc in sp0->filename (r->begs[0])
847 * copy len*data-size bytes
848 * get max from amp envs
849 */
850 mus_long_t err;
851
852 datumb = mus_bytes_per_sample(sp0->hdr->sample_type);
853 err = mus_write_header(r->filename, MUS_NEXT, r->srate, r->chans, drp->len * r->chans, sp0->hdr->sample_type, "region deferred temp");
854
855 if (err != MUS_NO_ERROR)
856 snd_error("can't write region temp file %s: %s", r->filename, snd_io_strerror());
857 else
858 {
859 int fdi, fdo;
860 mus_long_t oloc;
861 oloc = mus_header_data_location();
862 fdo = snd_reopen_write(r->filename);
863 lseek(fdo, oloc, SEEK_SET);
864 fdi = mus_file_open_read(sp0->filename);
865 if (fdi == -1)
866 snd_error("can't read region's original sound? %s: %s", sp0->filename, snd_io_strerror());
867 else
868 {
869 mus_long_t j, data_size;
870 char *buffer;
871
872 lseek(fdi, sp0->hdr->data_location + r->chans * datumb * r->begs[0], SEEK_SET);
873 data_size = drp->len * r->chans * datumb;
874 if (data_size > REPORTING_SIZE)
875 alloc_len = REPORTING_SIZE;
876 else alloc_len = data_size;
877 buffer = (char *)malloc(alloc_len * sizeof(char));
878 for (j = 0; j < data_size; j += alloc_len)
879 {
880 mus_long_t bytes;
881 ssize_t n;
882 bytes = data_size - j;
883 if (bytes > alloc_len)
884 bytes = alloc_len;
885
886 /* read and write return 0 to indicate end of file, apparently */
887 n = read(fdi, buffer, bytes);
888
889 if (n < 0)
890 fprintf(stderr, "IO error while reading region temp file: %d %s\n", (int)n, strerror(errno));
891 if (n > 0)
892 {
893 n = write(fdo, buffer, bytes);
894 if (n < 0)
895 fprintf(stderr, "IO error while writing region temp file: %d %s\n", (int)n, strerror(errno));
896 }
897 }
898 free(buffer);
899 snd_close(fdi, sp0->filename);
900 }
901 snd_close(fdo, r->filename);
902 }
903 }
904 else
905 {
906 io_error_t io_err = IO_NO_ERROR;
907 file_info *hdr = NULL;
908 int ofd;
909
910 hdr = make_temp_header(r->filename, r->srate, r->chans, 0, (char *)__func__);
911 ofd = open_temp_file(r->filename, r->chans, hdr, &io_err);
912 if (ofd == -1)
913 snd_error("%s region temp file %s: %s",
914 (io_err != IO_NO_ERROR) ? io_error_name(io_err) : "can't open",
915 r->filename,
916 snd_open_strerror());
917 else
918 {
919 sfs = (snd_fd **)calloc(r->chans, sizeof(snd_fd *));
920 data = (mus_float_t **)calloc(r->chans, sizeof(mus_float_t *));
921 datumb = mus_bytes_per_sample(hdr->sample_type);
922 /* here if peak_envs, maxamp exists */
923
924 alloc_len = len;
925 if (alloc_len > REPORTING_SIZE)
926 alloc_len = REPORTING_SIZE;
927
928 for (i = 0; i < r->chans; i++)
929 {
930 sfs[i] = init_sample_read_any(r->begs[i], drp->cps[i], READ_FORWARD, drp->edpos[i]);
931 data[i] = (mus_float_t *)calloc(alloc_len, sizeof(mus_float_t));
932 }
933
934 if ((r->chans == 1) &&
935 (r->ends[0] == (len - 1)))
936 {
937 snd_fd *sf;
938 mus_float_t *d;
939
940 sf = sfs[0];
941 d = data[0];
942 if (len <= REPORTING_SIZE)
943 {
944 samples_to_vct_with_reader(len, d, sf);
945 mus_file_write(ofd, 0, len - 1, 1, data);
946 }
947 else
948 {
949 int k;
950 sampler_set_safe(sf, len);
951 for (k = 0; k < len; k += alloc_len)
952 {
953 mus_long_t kdur, n;
954 int err;
955 kdur = len - k;
956 if (kdur > alloc_len) kdur = alloc_len;
957 for (n = 0; n < kdur; n++)
958 d[n] = read_sample(sf);
959 err = mus_file_write(ofd, 0, kdur - 1, 1, data);
960 if (err != MUS_NO_ERROR) break;
961 }
962 }
963 }
964 else
965 {
966 if (len <= REPORTING_SIZE)
967 {
968 for (i = 0; i < r->chans; i++)
969 samples_to_vct_with_reader(len, data[i], sfs[i]);
970 mus_file_write(ofd, 0, len - 1, r->chans, data);
971 }
972 else
973 {
974 int k;
975 for (i = 0; i < r->chans; i++)
976 sampler_set_safe(sfs[i], len);
977 for (k = 0; k < len; k += alloc_len)
978 {
979 int err;
980 mus_long_t kdur;
981
982 kdur = len - k;
983 if (kdur > alloc_len) kdur = alloc_len;
984 for (i = 0; i < r->chans; i++)
985 {
986 mus_long_t n;
987 snd_fd *p;
988 mus_float_t *buf;
989 buf = data[i];
990 p = sfs[i];
991 for (n = 0; n < kdur; n++)
992 buf[n] = read_sample(p);
993 }
994 err = mus_file_write(ofd, 0, kdur - 1, r->chans, data);
995 if (err != MUS_NO_ERROR) break;
996 }
997 }
998 }
999
1000 close_temp_file(r->filename, ofd, hdr->type, len * r->chans * datumb);
1001 for (i = 0; i < r->chans; i++) free(data[i]);
1002 for (i = 0; i < r->chans; i++) free_snd_fd(sfs[i]);
1003 free(sfs);
1004 free(data);
1005 data = NULL;
1006 }
1007 free_file_info(hdr);
1008 }
1009 r->dr = free_deferred_region(r->dr);
1010 }
1011
1012
sequester_deferred_regions(chan_info * cp,int edit_top)1013 void sequester_deferred_regions(chan_info *cp, int edit_top)
1014 {
1015 region *r;
1016 deferred_region *drp;
1017 int i;
1018 for (i = 0; i < regions_size; i++)
1019 {
1020 r = regions[i];
1021 if ((r) && (r->use_temp_file == REGION_DEFERRED))
1022 {
1023 int j;
1024 drp = r->dr;
1025 for (j = 0; j < drp->chans; j++)
1026 if ((drp->cps[j] == cp) &&
1027 (drp->edpos[j] > edit_top))
1028 {
1029 if (r->ends[j] > 1000000)
1030 status_report(cp->sound, "sequestering region %d...", r->id);
1031 deferred_region_to_temp_file(r);
1032 if (r->ends[j] > 1000000)
1033 clear_status_area(cp->sound);
1034 break;
1035 }
1036 }
1037 }
1038 }
1039
1040
init_region_read(mus_long_t beg,int n,int chan,read_direction_t direction)1041 snd_fd *init_region_read(mus_long_t beg, int n, int chan, read_direction_t direction)
1042 {
1043 /* conjure up a reasonable looking ed list and sound list */
1044 region *r;
1045 r = id_to_region(n);
1046 if ((r) && (chan < r->chans))
1047 {
1048 if ((beg == 0) &&
1049 (direction == READ_BACKWARD))
1050 beg = r->framples - 1;
1051 if (r->use_temp_file == REGION_DEFERRED)
1052 {
1053 deferred_region *drp;
1054 drp = r->dr;
1055 return(init_sample_read_any(r->begs[chan] + beg, drp->cps[chan], direction, drp->edpos[chan]));
1056 }
1057 else
1058 {
1059 make_region_readable(r);
1060 return(init_sample_read(beg, r->rsp->chans[chan], direction));
1061 }
1062 }
1063 return(NULL);
1064 }
1065
1066
cleanup_region_temp_files(void)1067 void cleanup_region_temp_files(void)
1068 { /* called upon exit to get rid of lingering region-related temp files */
1069 int i;
1070 for (i = 0; i < regions_size; i++)
1071 {
1072 region *r;
1073 r = regions[i];
1074 if ((r) &&
1075 (r->use_temp_file == REGION_FILE) &&
1076 (r->filename))
1077 {
1078 snd_remove(r->filename, REMOVE_FROM_CACHE);
1079 free(r->filename);
1080 r->filename = NULL;
1081 }
1082 }
1083 }
1084
1085
snd_regions(void)1086 int snd_regions(void)
1087 {
1088 int i, num;
1089 num = 0;
1090 for (i = 0; i < regions_size; i++)
1091 if (regions[i])
1092 num++;
1093 return(num);
1094 }
1095
1096
1097 /* (restore-region n chans len srate maxamp name start end filename [date-and-length]) */
1098
save_regions(FILE * fd)1099 void save_regions(FILE *fd)
1100 {
1101 int i;
1102 for (i = 0; i < regions_size; i++)
1103 {
1104 region *r;
1105 r = regions[i];
1106 if (r)
1107 {
1108 io_error_t io_err;
1109 char *newname;
1110 char *ofile = NULL;
1111
1112 if (r->use_temp_file == REGION_DEFERRED)
1113 deferred_region_to_temp_file(r);
1114 ofile = shorter_tempnam(save_dir(ss), "snd_save_");
1115 newname = run_save_state_hook(ofile);
1116 free(ofile);
1117
1118 io_err = copy_file(r->filename, newname);
1119 if (io_err != IO_NO_ERROR)
1120 {
1121 snd_warning("trying to save region %d (%s) in %s: %s, %s",
1122 r->id, r->filename, newname, io_error_name(io_err),
1123 strerror(ss->local_errno));
1124 }
1125 else
1126 {
1127 #if HAVE_RUBY
1128 fprintf(fd, "%s(%d, %d, %" print_mus_long ", %d, %.4f, \"%s\", \"%s\", \"%s\", ",
1129 "restore_region", i, r->chans, r->framples, r->srate, r->maxamp, r->name, r->start, r->end);
1130 fprintf(fd, " \"%s\", [%d, %" print_mus_long "])\n",
1131 newname,
1132 (int)mus_sound_write_date(newname),
1133 mus_sound_length(newname));
1134 #endif
1135 #if HAVE_SCHEME
1136 fprintf(fd, "(%s %d %d %" print_mus_long " %d %.4f \"%s\" \"%s\" \"%s\"",
1137 S_restore_region, i, r->chans, r->framples, r->srate, r->maxamp, r->name, r->start, r->end);
1138 fprintf(fd, " \"%s\" (list %d %" print_mus_long "))\n",
1139 newname,
1140 (int)mus_sound_write_date(newname),
1141 mus_sound_length(newname));
1142 #endif
1143 #if HAVE_FORTH
1144 fprintf(fd, "%d %d %" print_mus_long " %d %.4f \"%s\" \"%s\" \"%s\"",
1145 i, r->chans, r->framples, r->srate, r->maxamp, r->name, r->start, r->end);
1146 fprintf(fd, " \"%s\" '( %d %" print_mus_long " ) %s drop\n",
1147 newname,
1148 (int)mus_sound_write_date(newname),
1149 mus_sound_length(newname),
1150 S_restore_region);
1151 #endif
1152 }
1153 free(newname);
1154 }
1155 }
1156 }
1157
1158
region_edit(int pos)1159 void region_edit(int pos)
1160 {
1161 /* from region browser:
1162 * load region into temp file, load that into snd editor,
1163 * if 'save', save temp file and update region (browser also) (cancelling active display if any)
1164 * while editing, if delete in browser, cut backpointer in editor and signal it
1165 */
1166 region *r = NULL;
1167 if ((pos >= 0) &&
1168 (pos < regions_size) &&
1169 (regions[pos]))
1170 r = regions[pos];
1171 if (r)
1172 {
1173 if (r->editor_copy)
1174 snd_error("region %d already being edited", r->id);
1175 else
1176 {
1177 io_error_t io_err;
1178 char *temp_region_name;
1179 if (r->use_temp_file == REGION_DEFERRED)
1180 deferred_region_to_temp_file(r);
1181 temp_region_name = shorter_tempnam(temp_dir(ss), "region-");
1182 io_err = copy_file(r->filename, temp_region_name);
1183 if (io_err == IO_NO_ERROR)
1184 {
1185 snd_info *sp;
1186 ss->open_requestor = FROM_REGION_EDIT;
1187 sp = snd_open_file(temp_region_name, FILE_READ_WRITE);
1188 if (sp)
1189 {
1190 r->editor_copy = sp;
1191 r->editor_name = mus_strdup(temp_region_name);
1192 sp->edited_region = r;
1193 /* save backpointer so subsequent save affects region if still legit */
1194 /* also, since it's a temp file, if closed, delete temp */
1195 }
1196 else snd_error("edit region: can't open region %d temp sound %s: %s!",
1197 r->id, temp_region_name, snd_io_strerror());
1198 }
1199 else
1200 snd_error("edit region: can't save region %d in temp file (%s: %s)",
1201 r->id, temp_region_name, snd_io_strerror());
1202 free(temp_region_name);
1203 }
1204 }
1205 else snd_error("edit region: no region at position %d!", pos);
1206 }
1207
1208
clear_region_backpointer(snd_info * sp)1209 void clear_region_backpointer(snd_info *sp)
1210 {
1211 if (sp->edited_region)
1212 {
1213 region *r;
1214 r = sp->edited_region;
1215 if (r)
1216 {
1217 snd_remove(r->editor_name, REMOVE_FROM_CACHE);
1218 free(r->editor_name);
1219 r->editor_name = NULL;
1220 r->editor_copy = NULL;
1221 }
1222 sp->edited_region = NULL;
1223 }
1224 }
1225
1226
save_region_backpointer(snd_info * sp)1227 void save_region_backpointer(snd_info *sp)
1228 {
1229 /* region being edited, user chose 'save' */
1230 region *r;
1231 int i;
1232 io_error_t io_err;
1233
1234 r = sp->edited_region;
1235 /* update r's data in file, deleting old, redisplay if browser active etc */
1236
1237 if (r == regions[0]) deactivate_selection();
1238 free_region(r, CLEAR_REGION_DATA);
1239
1240 r->use_temp_file = REGION_FILE;
1241 r->maxamp = 0.0;
1242 r->maxamp_position = -1;
1243 r->framples = current_samples(sp->chans[0]);
1244
1245 for (i = 0; i < (int)sp->nchans; i++)
1246 {
1247 mus_float_t val;
1248 val = channel_maxamp(sp->chans[i], AT_CURRENT_EDIT_POSITION);
1249 if (val > r->maxamp) r->maxamp = val;
1250
1251 if (r->ends[i] > PEAK_ENV_CUTOFF)
1252 {
1253 chan_info *cp;
1254 cp = sp->chans[i];
1255 if (!r->peak_envs)
1256 r->peak_envs = (peak_env_info **)calloc(r->chans, sizeof(peak_env_info *));
1257 else
1258 {
1259 if (r->peak_envs[i])
1260 free_peak_env_info(r->peak_envs[i]);
1261 }
1262 /* if region file was edited, the peak_envs probably changed */
1263 r->peak_envs[i] = copy_peak_env_info(cp->edits[0]->peak_env, false);
1264 }
1265 }
1266
1267 /* make new region temp file */
1268 r->filename = snd_tempnam();
1269 io_err = copy_file(r->editor_name, r->filename);
1270 if (io_err != IO_NO_ERROR)
1271 {
1272 if (io_err == IO_CANT_OPEN_FILE)
1273 snd_error("can't find edited region temp file (%s: %s)", r->editor_name, snd_io_strerror());
1274 else snd_error("can't make region temp file (%s: %s)", r->filename, snd_io_strerror());
1275 }
1276 else
1277 {
1278 make_region_readable(r);
1279 if (region_browser_is_active())
1280 update_region_browser(true);
1281 }
1282 }
1283
1284
save_region(int rg,const char * name,mus_sample_t samp_type,mus_header_t head_type,const char * comment)1285 io_error_t save_region(int rg, const char *name, mus_sample_t samp_type, mus_header_t head_type, const char *comment)
1286 {
1287 region *r;
1288 io_error_t io_err = IO_NO_ERROR;
1289
1290 r = id_to_region(rg);
1291 if (r->use_temp_file == REGION_DEFERRED)
1292 deferred_region_to_temp_file(r);
1293
1294 io_err = snd_write_header(name, head_type, region_srate(rg), r->chans, r->chans * r->framples, samp_type, comment, NULL);
1295 if (io_err == IO_NO_ERROR)
1296 {
1297 mus_long_t oloc;
1298 int ofd;
1299
1300 oloc = mus_header_data_location();
1301 ofd = snd_reopen_write(name);
1302 if (ofd != -1)
1303 {
1304 int ifd;
1305 snd_file_open_descriptors(ofd, name, samp_type, oloc, r->chans, head_type);
1306 mus_file_set_clipping(ofd, clipping(ss));
1307 lseek(ofd, oloc, SEEK_SET);
1308 /* copy r->filename with possible header/sample type changes */
1309
1310 ifd = snd_open_read(r->filename);
1311 if (ifd != -1)
1312 {
1313 mus_long_t iloc, framples, cursamples;
1314 int chans, i, err = 0, ioff;
1315 mus_float_t **bufs;
1316
1317 chans = mus_sound_chans(r->filename);
1318 framples = mus_sound_samples(r->filename) / chans;
1319 iloc = mus_sound_data_location(r->filename);
1320
1321 snd_file_open_descriptors(ifd,
1322 r->filename,
1323 mus_sound_sample_type(r->filename),
1324 iloc,
1325 chans,
1326 mus_sound_header_type(r->filename));
1327 lseek(ifd, iloc, SEEK_SET);
1328 bufs = (mus_float_t **)calloc(chans, sizeof(mus_float_t *));
1329 for (i = 0; i < chans; i++) bufs[i] = (mus_float_t *)calloc(FILE_BUFFER_SIZE, sizeof(mus_float_t));
1330
1331 if (((framples * chans * mus_sound_datum_size(r->filename)) >> 10) > disk_kspace(name))
1332 snd_warning("not enough space to save region? -- need %" print_mus_long " bytes",
1333 framples * chans * mus_sound_datum_size(r->filename));
1334
1335 for (ioff = 0; ioff < framples; ioff += FILE_BUFFER_SIZE)
1336 {
1337 if ((ioff + FILE_BUFFER_SIZE) < framples)
1338 cursamples = FILE_BUFFER_SIZE;
1339 else cursamples = (framples - ioff);
1340 mus_file_read(ifd, ioff, cursamples, chans, bufs);
1341 err = mus_file_write(ofd, 0, cursamples - 1, chans, bufs);
1342 if (err != MUS_NO_ERROR)
1343 {
1344 snd_warning("write error during %s", S_save_region);
1345 break;
1346 }
1347 }
1348 err = mus_file_close(ifd);
1349 for (i = 0; i < chans; i++) free(bufs[i]);
1350 free(bufs);
1351
1352 if (err != 0)
1353 snd_warning("can't close %s input!", S_save_region);
1354 err = mus_file_close(ofd);
1355
1356 if (ss->file_monitor_ok)
1357 {
1358 if (err != 0)
1359 snd_error("%s %d: %s %s", S_save_region, rg, r->filename, snd_io_strerror());
1360 }
1361 else
1362 {
1363 #if USE_MOTIF
1364 if (err == 0)
1365 alert_new_file();
1366 else
1367 #else
1368 if (err != 0)
1369 #endif
1370 snd_error("%s %d: %s %s", S_save_region, rg, r->filename, snd_io_strerror());
1371 }
1372 }
1373 else snd_error("%s %d: %s %s", S_save_region, rg, r->filename, snd_io_strerror());
1374 }
1375 else snd_error("%s %d: %s %s", S_save_region, rg, name, snd_io_strerror());
1376 }
1377 else snd_error("%s %d: %s %s", S_save_region, rg, name, snd_io_strerror());
1378 return(io_err);
1379 }
1380
1381
1382 /* ---------------------------------------- region objects ---------------------------------------- */
1383
1384 typedef struct {
1385 int n;
1386 } xen_region;
1387
1388
1389 #define Xen_to_xen_region(arg) ((xen_region *)Xen_object_ref(arg))
1390
xen_region_to_int(Xen n)1391 int xen_region_to_int(Xen n)
1392 {
1393 xen_region *mx;
1394 mx = Xen_to_xen_region(n);
1395 return(mx->n);
1396 }
1397
1398
1399 static Xen_object_type_t xen_region_tag;
1400
xen_is_region(Xen obj)1401 bool xen_is_region(Xen obj)
1402 {
1403 return(Xen_c_object_is_type(obj, xen_region_tag));
1404 }
1405
1406 #if (!HAVE_SCHEME)
xen_region_free(xen_region * v)1407 static void xen_region_free(xen_region *v) {if (v) free(v);}
1408
Xen_wrap_free(xen_region,free_xen_region,xen_region_free)1409 Xen_wrap_free(xen_region, free_xen_region, xen_region_free)
1410 #else
1411 static s7_pointer s7_xen_region_free(s7_scheme *sc, s7_pointer obj)
1412 {
1413 xen_region *v;
1414 v = (xen_region *)s7_c_object_value(obj);
1415 if (v) free(v);
1416 return(NULL);
1417 }
1418 #endif
1419
1420
1421 static char *xen_region_to_string(xen_region *v)
1422 {
1423 #define REGION_PRINT_BUFFER_SIZE 64
1424 char *buf;
1425 if (!v) return(NULL);
1426 buf = (char *)calloc(REGION_PRINT_BUFFER_SIZE, sizeof(char));
1427 snprintf(buf, REGION_PRINT_BUFFER_SIZE, "#<region %d>", v->n);
1428 return(buf);
1429 }
1430
1431
1432 #if HAVE_FORTH || HAVE_RUBY
Xen_wrap_print(xen_region,print_xen_region,xen_region_to_string)1433 Xen_wrap_print(xen_region, print_xen_region, xen_region_to_string)
1434
1435 static Xen g_xen_region_to_string(Xen obj)
1436 {
1437 char *vstr;
1438 Xen result;
1439 #define S_xen_region_to_string "region->string"
1440 Xen_check_type(xen_is_region(obj), obj, 1, S_xen_region_to_string, "a region");
1441 vstr = xen_region_to_string(Xen_to_xen_region(obj));
1442 result = C_string_to_Xen_string(vstr);
1443 free(vstr);
1444 return(result);
1445 }
1446 #else
1447 #if HAVE_SCHEME
g_xen_region_to_string(s7_scheme * sc,s7_pointer args)1448 static s7_pointer g_xen_region_to_string(s7_scheme *sc, s7_pointer args)
1449 {
1450 char *vstr;
1451 Xen result;
1452 vstr = xen_region_to_string(Xen_to_xen_region(s7_car(args)));
1453 result = C_string_to_Xen_string(vstr);
1454 free(vstr);
1455 return(result);
1456 }
1457 #endif
1458 #endif
1459
1460
1461 #if (!HAVE_SCHEME)
xen_region_equalp(xen_region * v1,xen_region * v2)1462 static bool xen_region_equalp(xen_region *v1, xen_region *v2)
1463 {
1464 return((v1 == v2) ||
1465 (v1->n == v2->n));
1466 }
1467
equalp_xen_region(Xen obj1,Xen obj2)1468 static Xen equalp_xen_region(Xen obj1, Xen obj2)
1469 {
1470 if ((!(xen_is_region(obj1))) || (!(xen_is_region(obj2)))) return(Xen_false);
1471 return(C_bool_to_Xen_boolean(xen_region_equalp(Xen_to_xen_region(obj1), Xen_to_xen_region(obj2))));
1472 }
1473 #endif
1474
1475
xen_region_make(int n)1476 static xen_region *xen_region_make(int n)
1477 {
1478 xen_region *new_v;
1479 new_v = (xen_region *)malloc(sizeof(xen_region));
1480 new_v->n = n;
1481 return(new_v);
1482 }
1483
1484
new_xen_region(int n)1485 Xen new_xen_region(int n)
1486 {
1487 xen_region *mx;
1488 if (n < 0)
1489 return(Xen_false);
1490
1491 mx = xen_region_make(n);
1492 return(Xen_make_object(xen_region_tag, mx, 0, free_xen_region));
1493 }
1494
1495
1496 #if HAVE_SCHEME
s7_xen_region_is_equal(s7_scheme * sc,s7_pointer args)1497 static s7_pointer s7_xen_region_is_equal(s7_scheme *sc, s7_pointer args)
1498 {
1499 s7_pointer p1, p2;
1500 p1 = s7_car(args);
1501 p2 = s7_cadr(args);
1502 if (p1 == p2) return(s7_t(sc));
1503 if (s7_c_object_type(p2) == xen_region_tag)
1504 return(s7_make_boolean(sc, (((xen_region *)s7_c_object_value(p1))->n == ((xen_region *)s7_c_object_value(p2))->n)));
1505 return(s7_f(sc));
1506 }
1507
s7_xen_region_length(s7_scheme * sc,Xen args)1508 static Xen s7_xen_region_length(s7_scheme *sc, Xen args)
1509 {
1510 return(g_region_framples(s7_car(args), Xen_integer_zero));
1511 }
1512 #endif
1513
1514
init_xen_region(void)1515 static void init_xen_region(void)
1516 {
1517 #if HAVE_SCHEME
1518 xen_region_tag = s7_make_c_type(s7, "<region>");
1519 s7_c_type_set_gc_free(s7, xen_region_tag, s7_xen_region_free);
1520 s7_c_type_set_is_equal(s7, xen_region_tag, s7_xen_region_is_equal);
1521 s7_c_type_set_length(s7, xen_region_tag, s7_xen_region_length);
1522 s7_c_type_set_to_string(s7, xen_region_tag, g_xen_region_to_string);
1523 #else
1524 #if HAVE_RUBY
1525 xen_region_tag = Xen_make_object_type("XenRegion", sizeof(xen_region));
1526 #else
1527 xen_region_tag = Xen_make_object_type("Region", sizeof(xen_region));
1528 #endif
1529 #endif
1530
1531 #if HAVE_FORTH
1532 fth_set_object_inspect(xen_region_tag, print_xen_region);
1533 fth_set_object_dump(xen_region_tag, g_xen_region_to_string);
1534 fth_set_object_equal(xen_region_tag, equalp_xen_region);
1535 fth_set_object_free(xen_region_tag, free_xen_region);
1536 #endif
1537
1538 #if HAVE_RUBY
1539 rb_define_method(xen_region_tag, "to_s", Xen_procedure_cast print_xen_region, 0);
1540 rb_define_method(xen_region_tag, "eql?", Xen_procedure_cast equalp_xen_region, 1);
1541 rb_define_method(xen_region_tag, "==", Xen_procedure_cast equalp_xen_region, 1);
1542 rb_define_method(xen_region_tag, "to_str", Xen_procedure_cast g_xen_region_to_string, 0);
1543 #endif
1544 }
1545
1546 /* -------------------------------------------------------------------------------- */
1547
1548
g_integer_to_region(Xen n)1549 static Xen g_integer_to_region(Xen n)
1550 {
1551 #define H_integer_to_region "(" S_integer_to_region " n) returns a region object corresponding to the given integer"
1552 region* r;
1553 Xen_check_type(Xen_is_integer(n), n, 1, S_integer_to_region, "an integer");
1554 r = id_to_region(Xen_integer_to_C_int(n));
1555 if (r)
1556 return(new_xen_region(r->id));
1557 return(Xen_false);
1558 }
1559
1560
g_region_to_integer(Xen n)1561 static Xen g_region_to_integer(Xen n)
1562 {
1563 #define H_region_to_integer "(" S_region_to_integer " id) returns the integer corresponding to the given region"
1564 Xen_check_type(xen_is_region(n), n, 1, S_region_to_integer, "a region");
1565 return(C_int_to_Xen_integer(xen_region_to_int(n)));
1566 }
1567
1568
snd_no_such_region_error(const char * caller,Xen n)1569 static Xen snd_no_such_region_error(const char *caller, Xen n)
1570 {
1571 Xen_error(Xen_make_error_type("no-such-region"),
1572 Xen_list_3(C_string_to_Xen_string("~A: no such region, ~A"),
1573 C_string_to_Xen_string(caller),
1574 n));
1575 return(Xen_false);
1576 }
1577
1578
1579 /* Xen pos, Xen chans, Xen len, Xen srate, Xen maxamp, Xen name, Xen start, Xen end, Xen filename, Xen date */
1580
g_restore_region(Xen args)1581 static Xen g_restore_region(Xen args)
1582 {
1583 /* internal function used by save-state mechanism -- not intended for external use */
1584 region *r;
1585 int i, regn;
1586 Xen arg, pos, chans, len, srate, maxamp, name, start, end, filename, date;
1587
1588 Xen_check_type(Xen_list_length(args) == 10, args, 0, S_restore_region, "10 items");
1589 arg = args;
1590 pos = Xen_car(arg);
1591 Xen_check_type(Xen_is_integer(pos), pos, 1, S_restore_region, "a region id");
1592
1593 arg = Xen_cdr(arg);
1594 chans = Xen_car(arg);
1595 Xen_check_type(Xen_is_integer(chans), chans, 2, S_restore_region, "an integer");
1596
1597 arg = Xen_cdr(arg);
1598 len = Xen_car(arg);
1599 Xen_check_type(Xen_is_integer(len), len, 3, S_restore_region, "an integer");
1600
1601 arg = Xen_cdr(arg);
1602 srate = Xen_car(arg);
1603 Xen_check_type(Xen_is_integer(srate), srate, 4, S_restore_region, "an integer");
1604
1605 arg = Xen_cdr(arg);
1606 maxamp = Xen_car(arg);
1607 Xen_check_type(Xen_is_double(maxamp), maxamp, 5, S_restore_region, "a double");
1608
1609 arg = Xen_cdr(arg);
1610 name = Xen_car(arg);
1611 Xen_check_type(Xen_is_string(name), name, 6, S_restore_region, "a string");
1612
1613 arg = Xen_cdr(arg);
1614 start = Xen_car(arg);
1615 Xen_check_type(Xen_is_string(start), start, 7, S_restore_region, "a string");
1616
1617 arg = Xen_cdr(arg);
1618 end = Xen_car(arg);
1619 Xen_check_type(Xen_is_string(end), end, 8, S_restore_region, "a string");
1620
1621 arg = Xen_cdr(arg);
1622 filename = Xen_car(arg);
1623 Xen_check_type(Xen_is_string(filename), filename, 9, S_restore_region, "a string");
1624
1625 arg = Xen_cdr(arg);
1626 date = Xen_car(arg);
1627 Xen_check_type(Xen_is_list(date) && (Xen_list_length(date) == 2), date, 10, S_restore_region, "a list: '(time bytes)");
1628
1629 check_saved_temp_file("region", filename, date);
1630
1631 r = (region *)calloc(1, sizeof(region));
1632 regn = Xen_integer_to_C_int(pos);
1633 if (regions[regn]) free_region(regions[regn], COMPLETE_DELETION);
1634 regions[regn] = r;
1635 r->id = region_id_ctr++;
1636 r->maxamp = Xen_real_to_C_double(maxamp);
1637 r->maxamp_position = -1; /* not saved/restored */
1638 r->chans = Xen_integer_to_C_int(chans);
1639 r->rsp = NULL;
1640 r->editor_copy = NULL;
1641 r->editor_name = NULL;
1642 r->framples = Xen_llong_to_C_llong(len);
1643 r->srate = Xen_integer_to_C_int(srate);
1644 r->name = mus_strdup(Xen_string_to_C_string(name));
1645 r->start = mus_strdup(Xen_string_to_C_string(start));
1646 r->end = mus_strdup(Xen_string_to_C_string(end));
1647 r->use_temp_file = REGION_FILE;
1648 r->filename = mus_strdup(Xen_string_to_C_string(filename));
1649
1650 /* bugfix for saved regions -- thanks to Tito Latini */
1651 r->begs = (mus_long_t *)calloc(r->chans, sizeof(mus_long_t));
1652 r->ends = (mus_long_t *)calloc(r->chans, sizeof(mus_long_t));
1653 for (i = 0; i < r->chans; i++)
1654 {
1655 r->begs[i] = 0;
1656 r->ends[i] = r->framples - 1;
1657 }
1658
1659 reflect_regions_in_region_browser();
1660 return(C_int_to_Xen_integer(r->id));
1661 }
1662
1663
g_insert_region(Xen reg_n,Xen samp_n,Xen snd_n,Xen chn_n)1664 static Xen g_insert_region(Xen reg_n, Xen samp_n, Xen snd_n, Xen chn_n) /* opt reg_n */
1665 {
1666 #define H_insert_region "(" S_insert_region " region :optional (start-samp 0) snd chn): \
1667 insert region data into snd's channel chn starting at start-samp"
1668
1669 chan_info *cp;
1670 int rg;
1671 mus_long_t samp;
1672 io_error_t err = IO_NO_ERROR;
1673
1674 Xen_check_type(xen_is_region(reg_n), reg_n, 1, S_insert_region, "a region id");
1675 Xen_check_type(Xen_is_integer_or_unbound(samp_n), samp_n, 2, S_insert_region, "an integer");
1676
1677 Snd_assert_channel(S_insert_region, snd_n, chn_n, 3);
1678 cp = get_cp(snd_n, chn_n, S_insert_region);
1679 if (!cp) return(Xen_false);
1680
1681 rg = Xen_region_to_C_int(reg_n);
1682 if (!(region_ok(rg)))
1683 return(snd_no_such_region_error(S_insert_region, reg_n));
1684
1685 samp = beg_to_sample(samp_n, S_insert_region);
1686 err = paste_region_2(rg, cp, false, samp);
1687
1688 if (is_serious_io_error(err))
1689 Xen_error(Xen_make_error_type("IO-error"),
1690 Xen_list_3(C_string_to_Xen_string(S_insert_region ": can't edit ~A (region access problem?), ~A"),
1691 C_string_to_Xen_string(cp->sound->filename),
1692 C_string_to_Xen_string(io_error_name(err))));
1693 update_graph(cp);
1694 return(reg_n);
1695 }
1696
1697
g_max_regions(void)1698 static Xen g_max_regions(void)
1699 {
1700 #define H_max_regions "(" S_max_regions "): max number of regions saved on the region list"
1701 return(C_int_to_Xen_integer(max_regions(ss)));
1702 }
1703
1704
g_set_max_regions(Xen n)1705 static Xen g_set_max_regions(Xen n)
1706 {
1707 int regs;
1708 Xen_check_type(Xen_is_integer(n), n, 1, S_set S_max_regions, "an integer");
1709
1710 regs = Xen_integer_to_C_int(n);
1711 if (regs < 0)
1712 Xen_out_of_range_error(S_set S_max_regions, 1, n, S_max_regions "negative?");
1713
1714 set_max_regions(regs);
1715 return(C_int_to_Xen_integer(max_regions(ss)));
1716 }
1717
1718
g_is_region(Xen n)1719 static Xen g_is_region(Xen n)
1720 {
1721 #define H_is_region "(" S_is_region " reg): " PROC_TRUE " if region is active"
1722 return(C_bool_to_Xen_boolean((xen_is_region(n)) && (region_ok(Xen_region_to_C_int(n)))));
1723 }
1724
1725
g_region_framples(Xen n,Xen chan)1726 Xen g_region_framples(Xen n, Xen chan)
1727 {
1728 region *r;
1729 int rg, chn;
1730 #define H_region_framples "(" S_region_framples " reg :optional (chan 0)): region length in framples"
1731
1732 Xen_check_type(xen_is_region(n), n, 1, S_region_framples, "a region");
1733 Xen_check_type(Xen_is_integer_or_unbound(chan), chan, 2, S_region_framples, "an integer");
1734
1735 rg = Xen_region_to_C_int(n);
1736 if (!(region_ok(rg)))
1737 return(snd_no_such_region_error(S_region_framples, n));
1738
1739 if (!Xen_is_bound(chan))
1740 return(C_llong_to_Xen_llong(region_len(rg)));
1741 chn = Xen_integer_to_C_int(chan);
1742 if ((chn < 0) || (chn >= region_chans(rg)))
1743 return(snd_no_such_channel_error(S_region_framples, Xen_list_1(n), chan));
1744
1745 r = id_to_region(rg);
1746 return(C_llong_to_Xen_llong(r->ends[chn] + 1));
1747 }
1748
1749
g_region_position(Xen n,Xen chan)1750 static Xen g_region_position(Xen n, Xen chan)
1751 {
1752 region *r;
1753 int rg, chn = 0;
1754 #define H_region_position "(" S_region_position " reg :optional (chan 0)): region's position in the original sound"
1755
1756 Xen_check_type(xen_is_region(n), n, 1, S_region_position, "a region");
1757 Xen_check_type(Xen_is_integer_or_unbound(chan), chan, 2, S_region_position, "an integer");
1758
1759 rg = Xen_region_to_C_int(n);
1760 if (!(region_ok(rg)))
1761 return(snd_no_such_region_error(S_region_position, n));
1762
1763 if (Xen_is_integer(chan)) chn = Xen_integer_to_C_int(chan);
1764 if ((chn < 0) || (chn >= region_chans(rg)))
1765 return(snd_no_such_channel_error(S_region_position, Xen_list_1(n), chan));
1766
1767 r = id_to_region(rg);
1768 return(C_llong_to_Xen_llong(r->begs[chn]));
1769 }
1770
1771
1772 typedef enum {REGION_SRATE, REGION_CHANS, REGION_MAXAMP, REGION_FORGET, REGION_MAXAMP_POSITION, REGION_HOME} region_field_t;
1773
region_get(region_field_t field,Xen n,const char * caller)1774 static Xen region_get(region_field_t field, Xen n, const char *caller)
1775 {
1776 int rg;
1777 rg = Xen_region_to_C_int(n);
1778 if (!(region_ok(rg)))
1779 return(snd_no_such_region_error(caller, n));
1780
1781 switch (field)
1782 {
1783 case REGION_SRATE: return(C_int_to_Xen_integer(region_srate(rg)));
1784 case REGION_CHANS: return(C_int_to_Xen_integer(region_chans(rg)));
1785 case REGION_MAXAMP: return(C_double_to_Xen_real(region_maxamp(rg)));
1786 case REGION_MAXAMP_POSITION: return(C_llong_to_Xen_llong(region_maxamp_position(rg)));
1787 case REGION_FORGET: delete_region_and_update_browser(region_id_to_list_position(rg)); return(n);
1788 case REGION_HOME:
1789 {
1790 region *r;
1791 r = id_to_region(rg);
1792 if (r)
1793 return(Xen_list_3(C_string_to_Xen_string(r->name),
1794 C_llong_to_Xen_llong(r->begs[0]),
1795 C_llong_to_Xen_llong(r->ends[0] + 1)));
1796 }
1797 break;
1798 default: break;
1799 }
1800 return(Xen_false);
1801 }
1802
1803
g_region_srate(Xen n)1804 Xen g_region_srate(Xen n)
1805 {
1806 #define H_region_srate "(" S_region_srate " reg): region (nominal) srate"
1807 Xen_check_type(xen_is_region(n), n, 1, S_region_srate, "a region");
1808 return(region_get(REGION_SRATE, n, S_region_srate));
1809 }
1810
1811
g_region_chans(Xen n)1812 Xen g_region_chans(Xen n)
1813 {
1814 #define H_region_chans "(" S_region_chans " reg): region channels"
1815 Xen_check_type(xen_is_region(n), n, 1, S_region_chans, "a region");
1816 return(region_get(REGION_CHANS, n, S_region_chans));
1817 }
1818
1819
g_region_home(Xen n)1820 static Xen g_region_home(Xen n)
1821 {
1822 #define H_region_home "(" S_region_home " reg): a list with the region source sound name and position info"
1823 Xen_check_type(xen_is_region(n), n, 1, S_region_home, "a region");
1824 return(region_get(REGION_HOME, n, S_region_home));
1825 }
1826
1827
g_region_maxamp(Xen n)1828 Xen g_region_maxamp(Xen n)
1829 {
1830 #define H_region_maxamp "(" S_region_maxamp " reg): region maxamp"
1831 Xen_check_type(xen_is_region(n), n, 1, S_region_maxamp, "a region");
1832 return(region_get(REGION_MAXAMP, n, S_region_maxamp));
1833 }
1834
1835
g_region_maxamp_position(Xen n)1836 static Xen g_region_maxamp_position(Xen n)
1837 {
1838 #define H_region_maxamp_position "(" S_region_maxamp_position " reg): first sample where region maxamp occurs"
1839 Xen_check_type(xen_is_region(n), n, 1, S_region_maxamp_position, "a region");
1840 return(region_get(REGION_MAXAMP_POSITION, n, S_region_maxamp_position));
1841 }
1842
1843
g_forget_region(Xen n)1844 static Xen g_forget_region(Xen n)
1845 {
1846 #define H_forget_region "(" S_forget_region " reg): remove region from the region list"
1847 Xen_check_type(xen_is_region(n), n, 1, S_forget_region, "a region");
1848 return(region_get(REGION_FORGET, n, S_forget_region));
1849 }
1850
1851
g_play_region(Xen n,play_process_t back,Xen stop_proc)1852 Xen g_play_region(Xen n, play_process_t back, Xen stop_proc)
1853 {
1854 int rg;
1855 region *r;
1856 rg = Xen_region_to_C_int(n);
1857 r = id_to_region(rg);
1858 if (r)
1859 {
1860 make_region_readable(r);
1861 play_region_1(rg, back, stop_proc);
1862 return(n);
1863 }
1864 return(snd_no_such_region_error(S_play, n));
1865 }
1866
1867
g_regions(void)1868 static Xen g_regions(void)
1869 {
1870 #define H_regions "(" S_regions "): current active regions (a list of region ids)"
1871 int i;
1872 Xen result;
1873 result = Xen_empty_list;
1874 for (i = (regions_size - 1); i >= 0; i--)
1875 if (regions[i])
1876 result = Xen_cons(C_int_to_Xen_region(regions[i]->id), result);
1877 return(result);
1878 }
1879
1880
g_make_region(Xen beg,Xen end,Xen snd_n,Xen chn_n)1881 static Xen g_make_region(Xen beg, Xen end, Xen snd_n, Xen chn_n)
1882 {
1883 #define H_make_region "(" S_make_region " :optional beg end snd chn): make a new region between beg and end in snd. \
1884 If chn is " PROC_TRUE ", all chans are included, taking the snd sync field into account if it's not 0. If no args are passed, the current \
1885 selection is used."
1886 int id = INVALID_REGION;
1887
1888 if (max_regions(ss) <= 0) return(Xen_false);
1889 if (!Xen_is_bound(beg))
1890 id = make_region_from_selection();
1891 else
1892 {
1893 sync_info *si = NULL;
1894 snd_info *sp;
1895 mus_long_t ibeg, iend;
1896 mus_long_t *ends = NULL;
1897 int i;
1898
1899 Xen_check_type(Xen_is_integer(beg), beg, 1, S_make_region, "an integer");
1900 Xen_check_type(Xen_is_integer(end), end, 2, S_make_region, "an integer");
1901
1902 ibeg = beg_to_sample(beg, S_make_region);
1903 iend = beg_to_sample(end, S_make_region);
1904
1905 if (Xen_is_true(chn_n))
1906 {
1907 /* all chans and all sync'd chans if sync not 0 */
1908 sp = get_sp(snd_n);
1909 if (sp)
1910 {
1911 int old_sync;
1912 old_sync = sp->sync;
1913 if (sp->sync == 0)
1914 {
1915 /* set up temp sync for snd_sync */
1916 sp->sync = ss->sound_sync_max + 1;
1917 ss->sound_sync_max++;
1918 }
1919 si = snd_sync(sp->sync);
1920 sp->sync = old_sync;
1921 }
1922 else return(snd_no_such_sound_error(S_make_region, snd_n));
1923 }
1924 else
1925 {
1926 chan_info *cp;
1927 cp = get_cp(snd_n, chn_n, S_make_region);
1928 si = make_simple_sync(cp, ibeg);
1929 }
1930
1931 ends = (mus_long_t *)calloc(si->chans, sizeof(mus_long_t));
1932 for (i = 0; i < si->chans; i++)
1933 {
1934 if (current_samples(si->cps[i]) - 1 < iend)
1935 ends[i] = current_samples(si->cps[i]) - 1;
1936 else ends[i] = iend;
1937 si->begs[i] = ibeg;
1938 if (ends[i] < ibeg)
1939 {
1940 free(ends);
1941 ends = NULL;
1942 si = free_sync_info(si);
1943 Xen_out_of_range_error(S_make_region, 1, end, "end < beg?");
1944 }
1945 }
1946 if (ends)
1947 {
1948 id = define_region(si, ends);
1949 if (selection_creates_region(ss))
1950 reactivate_selection(si->cps[0], si->begs[0], ends[0]);
1951 free_sync_info(si);
1952 free(ends);
1953 }
1954 }
1955 return(C_int_to_Xen_region(id));
1956 }
1957
1958
save_region_to_xen_error(const char * msg,void * data)1959 static void save_region_to_xen_error(const char *msg, void *data)
1960 {
1961 redirect_snd_error_to(NULL, NULL);
1962 Xen_error(Xen_make_error_type("cannot-save"),
1963 Xen_list_2(C_string_to_Xen_string(S_save_region ": can't save ~S"),
1964 C_string_to_Xen_string(msg)));
1965 }
1966
1967 #define H_save_region "(" S_save_region " region file sample-type header-type comment): save region in file \
1968 using sample-type (default depends on machine byte order), header-type (" S_mus_next "), and comment"
1969
1970 #if HAVE_SCHEME
g_save_region(s7_scheme * sc,s7_pointer args)1971 static s7_pointer g_save_region(s7_scheme *sc, s7_pointer args)
1972 {
1973 mus_header_t head_type;
1974 mus_sample_t samp_type;
1975 int rg;
1976 const char *com, *file;
1977 char *name;
1978 s7_pointer p, fp, res;
1979
1980 fp = s7_car(args);
1981 if (!xen_is_region(fp))
1982 return(s7_wrong_type_arg_error(sc, S_save_region, 1, fp, "a region"));
1983 rg = Xen_region_to_C_int(fp);
1984 if (!(region_ok(rg)))
1985 return(snd_no_such_region_error(S_save_region, fp));
1986
1987 fp = s7_cadr(args);
1988 if (fp == Xen_false)
1989 Xen_error(Xen_make_error_type("IO-error"),
1990 Xen_list_1(C_string_to_Xen_string(S_save_region ": no output file?")));
1991 if (!s7_is_string(fp))
1992 return(s7_wrong_type_arg_error(sc, S_save_region, 2, fp, "a string"));
1993 file = s7_string(fp);
1994 name = mus_expand_filename(file);
1995 res = fp;
1996
1997 p = s7_cddr(args);
1998 fp = s7_car(p);
1999 if (fp == Xen_false)
2000 samp_type = MUS_OUT_SAMPLE_TYPE;
2001 else
2002 {
2003 if (!s7_is_integer(fp))
2004 return(s7_wrong_type_arg_error(sc, S_save_selection, 3, fp, "an integer"));
2005 samp_type = (mus_sample_t)s7_integer(fp);
2006 }
2007
2008 fp = s7_cadr(p);
2009 if (fp == Xen_false)
2010 head_type = MUS_NEXT;
2011 else
2012 {
2013 if (!s7_is_integer(fp))
2014 return(s7_wrong_type_arg_error(sc, S_save_selection, 4, fp, "an integer"));
2015 head_type = (mus_header_t)s7_integer(fp);
2016 }
2017
2018 if (!(mus_header_writable(head_type, samp_type)))
2019 {
2020 if (mus_header_writable(MUS_NEXT, samp_type))
2021 head_type = MUS_NEXT;
2022 else
2023 {
2024 if (mus_header_writable(MUS_RIFF, samp_type))
2025 head_type = MUS_RIFF;
2026 else head_type = MUS_RAW;
2027 }
2028 }
2029
2030 fp = s7_caddr(p);
2031 if (fp == Xen_false)
2032 com = NULL;
2033 else
2034 {
2035 if (!s7_is_string(fp))
2036 return(s7_wrong_type_arg_error(sc, S_save_selection, 5, fp, "a string"));
2037 com = s7_string(fp);
2038 }
2039
2040 redirect_snd_error_to(save_region_to_xen_error, NULL); /* could perhaps pass name here for free in case of error */
2041 save_region(rg, name, samp_type, head_type, com);
2042 redirect_snd_error_to(NULL, NULL);
2043
2044 if (name) free(name);
2045 return(res);
2046 }
2047 #else
2048 static Xen kw_header_type, kw_comment, kw_file, kw_sample_type;
2049
init_region_keywords(void)2050 static void init_region_keywords(void)
2051 {
2052 kw_header_type = Xen_make_keyword("header-type");
2053 kw_sample_type = Xen_make_keyword("sample-type");
2054 kw_comment = Xen_make_keyword("comment");
2055 kw_file = Xen_make_keyword("file");
2056 }
2057
g_save_region(Xen n,Xen arg1,Xen arg2,Xen arg3,Xen arg4,Xen arg5,Xen arg6,Xen arg7,Xen arg8)2058 static Xen g_save_region(Xen n, Xen arg1, Xen arg2, Xen arg3, Xen arg4, Xen arg5, Xen arg6, Xen arg7, Xen arg8)
2059 {
2060 char *name = NULL;
2061 const char *file = NULL, *com = NULL;
2062 int rg, true_args;
2063 mus_sample_t sample_type = MUS_OUT_SAMPLE_TYPE;
2064 mus_header_t header_type = MUS_NEXT;
2065 Xen args[8];
2066 Xen keys[4];
2067 int orig_arg[4] = {0, 0, 0, 0};
2068 int vals;
2069
2070 keys[0] = kw_file;
2071 keys[1] = kw_sample_type;
2072 keys[2] = kw_header_type;
2073 keys[3] = kw_comment;
2074 args[0] = arg1; args[1] = arg2; args[2] = arg3; args[3] = arg4; args[4] = arg5; args[5] = arg6; args[6] = arg7; args[7] = arg8;
2075 for (true_args = 0; true_args < 8; true_args++)
2076 if (!Xen_is_bound(args[true_args]))
2077 break;
2078 Xen_check_type(xen_is_region(n), n, 1, S_save_region, "a region id");
2079
2080 rg = Xen_region_to_C_int(n);
2081 if (!(region_ok(rg)))
2082 return(snd_no_such_region_error(S_save_region, n));
2083
2084 vals = mus_optkey_unscramble(S_save_region, true_args, 4, keys, args, orig_arg);
2085 if (vals > 0)
2086 {
2087 file = mus_optkey_to_string(keys[0], S_save_region, orig_arg[0], NULL);
2088 sample_type = (mus_sample_t)mus_optkey_to_int(keys[1], S_save_region, orig_arg[1], (int)sample_type);
2089 header_type = (mus_header_t)mus_optkey_to_int(keys[2], S_save_region, orig_arg[2], (int)header_type);
2090 com = mus_optkey_to_string(keys[3], S_save_region, orig_arg[3], NULL);
2091 }
2092
2093 if (!file)
2094 Xen_error(Xen_make_error_type("IO-error"),
2095 Xen_list_1(C_string_to_Xen_string(S_save_region ": no output file?")));
2096
2097 name = mus_expand_filename(file);
2098
2099 if (!(mus_header_writable(header_type, sample_type)))
2100 {
2101 if (mus_header_writable(MUS_NEXT, sample_type))
2102 header_type = MUS_NEXT;
2103 else
2104 {
2105 if (mus_header_writable(MUS_RIFF, sample_type))
2106 header_type = MUS_RIFF;
2107 else header_type = MUS_RAW;
2108 }
2109 }
2110
2111 redirect_snd_error_to(save_region_to_xen_error, NULL); /* could perhaps pass name here for free in case of error */
2112 save_region(rg, name, sample_type, header_type, com);
2113 redirect_snd_error_to(NULL, NULL);
2114
2115 if (name) free(name);
2116 return(args[orig_arg[0] - 1]); /* -> filename, parallel save-selection */
2117 }
2118 #endif
2119
g_mix_region(Xen reg_n,Xen chn_samp_n,Xen snd_n,Xen chn_n,Xen reg_chn)2120 static Xen g_mix_region(Xen reg_n, Xen chn_samp_n, Xen snd_n, Xen chn_n, Xen reg_chn)
2121 {
2122 #define H_mix_region "(" S_mix_region " region :optional (chn-samp 0) snd chn (region-chan " PROC_TRUE ")): \
2123 mix region's channel region-chan (or all chans if region-chan is " PROC_TRUE ") into snd's channel chn starting at chn-samp; \
2124 it returns a list of the new mixes"
2125
2126 chan_info *cp;
2127 mus_long_t samp;
2128 io_error_t err = IO_NO_ERROR;
2129 int i, rg, id = -1, reg_chan = 0, reg_chans = 0;
2130 Xen result = Xen_empty_list;
2131
2132 Xen_check_type(xen_is_region(reg_n), reg_n, 1, S_mix_region, "a region");
2133 Xen_check_type(Xen_is_integer_or_unbound(chn_samp_n), chn_samp_n, 2, S_mix_region, "an integer");
2134 Xen_check_type(Xen_is_integer_boolean_or_unbound(reg_chn), reg_chn, 5, S_mix_region, "an integer or " PROC_TRUE);
2135 Snd_assert_channel(S_mix_region, snd_n, chn_n, 3);
2136
2137 rg = Xen_region_to_C_int(reg_n);
2138 if (!(region_ok(rg)))
2139 return(snd_no_such_region_error(S_mix_region, reg_n));
2140
2141 cp = get_cp(snd_n, chn_n, S_mix_region);
2142 if (!cp) return(Xen_false);
2143
2144 if (Xen_is_bound(chn_samp_n))
2145 samp = beg_to_sample(chn_samp_n, S_mix_region);
2146 else samp = cursor_sample(cp);
2147
2148 if (Xen_is_integer(reg_chn))
2149 reg_chan = Xen_integer_to_C_int(reg_chn);
2150
2151 id = paste_region_1(rg, cp, true, samp, &err, reg_chan, ®_chans);
2152
2153 /* id might legitmately be invalid mix id if with_mix_tags is #f or virtual mix not ok */
2154 if (is_serious_io_error(err))
2155 Xen_error(Xen_make_error_type("IO-error"),
2156 Xen_list_2(C_string_to_Xen_string(S_mix_region ": can't edit, ~A"),
2157 C_string_to_Xen_string(io_error_name(err))));
2158
2159 if (id == -1) return(Xen_false);
2160 for (i = 0; i < reg_chans; i++)
2161 result = Xen_cons(new_xen_mix(id + i), result);
2162
2163 return(Xen_list_reverse(result));
2164 }
2165
2166
g_region_sample(Xen reg_n,Xen samp_n,Xen chn_n)2167 static Xen g_region_sample(Xen reg_n, Xen samp_n, Xen chn_n)
2168 {
2169 #define H_region_sample "(" S_region_sample " region samp :optional (chan 0)): region's sample at samp in chan"
2170
2171 int rg, chan = 0;
2172 mus_long_t samp;
2173
2174 Xen_check_type(xen_is_region(reg_n), reg_n, 1, S_region_sample, "a region");
2175 Xen_check_type(Xen_is_integer(samp_n), samp_n, 2, S_region_sample, "an integer");
2176 Xen_check_type(Xen_is_integer_or_unbound(chn_n), chn_n, 3, S_region_sample, "an integer");
2177
2178 if (Xen_is_integer(chn_n)) chan = Xen_integer_to_C_int(chn_n);
2179 rg = Xen_region_to_C_int(reg_n);
2180 if (!(region_ok(rg)))
2181 return(snd_no_such_region_error(S_region_sample, reg_n));
2182
2183 samp = beg_to_sample(samp_n, S_region_sample);
2184 if ((chan >= 0) && (chan < region_chans(rg)))
2185 return(C_double_to_Xen_real(region_sample(rg, chan, samp)));
2186 return(snd_no_such_channel_error(S_region_sample, Xen_list_1(reg_n), chn_n));
2187 }
2188
2189
g_region_to_vct(Xen reg_n,Xen beg_n,Xen num,Xen chn_n,Xen v)2190 Xen g_region_to_vct(Xen reg_n, Xen beg_n, Xen num, Xen chn_n, Xen v)
2191 {
2192 #define H_region_to_vct "(" S_region_to_vct " region :optional (beg 0) samps (chan 0) v): \
2193 write region's samples starting at beg for samps in channel chan to " S_vct " v; return v (or create a new one)"
2194
2195 int reg, chn = 0;
2196 mus_long_t len = 0;
2197 vct *v1 = xen_to_vct(v);
2198
2199 Xen_check_type(xen_is_region(reg_n), reg_n, 1, S_region_to_vct, "a region");
2200 Xen_check_type(Xen_is_integer_or_unbound(beg_n), beg_n, 2, S_region_to_vct, "an integer");
2201 Xen_check_type(Xen_is_integer_or_unbound(num), num, 3, S_region_to_vct, "an integer");
2202 Xen_check_type(Xen_is_integer_or_unbound(chn_n), chn_n, 4, S_region_to_vct, "an integer");
2203
2204 reg = Xen_region_to_C_int(reg_n);
2205 if (!(region_ok(reg)))
2206 return(snd_no_such_region_error(S_region_to_vct, reg_n));
2207
2208 if (Xen_is_integer(chn_n))
2209 {
2210 chn = Xen_integer_to_C_int(chn_n);
2211 if ((chn < 0) || (chn >= region_chans(reg)))
2212 return(snd_no_such_channel_error(S_region_to_vct, Xen_list_1(reg_n), chn_n));
2213 }
2214 if (Xen_is_integer(num))
2215 {
2216 len = Xen_llong_to_C_llong(num);
2217 if (len < 0)
2218 Xen_out_of_range_error(S_region_to_vct, 2, num, "length < 0?");
2219 }
2220 if ((len == 0) || (len > region_len(reg)))
2221 len = region_len(reg);
2222
2223 if (len > 0)
2224 {
2225 mus_float_t *data;
2226 mus_long_t beg;
2227 beg = beg_to_sample(beg_n, S_region_to_vct);
2228 if (beg >= region_len(reg))
2229 return(Xen_false);
2230 if (v1)
2231 {
2232 data = mus_vct_data(v1);
2233 if (len > mus_vct_length(v1)) len = mus_vct_length(v1);
2234 }
2235 else
2236 {
2237 if ((beg + len) > region_len(reg))
2238 len = region_len(reg) - beg;
2239 data = (mus_float_t *)calloc(len, sizeof(mus_float_t));
2240 }
2241 region_samples(reg, chn, beg, len, data);
2242 if (v1)
2243 return(v);
2244 else return(xen_make_vct(len, data));
2245 }
2246 return(Xen_false);
2247 }
2248
2249
g_region_graph_style(void)2250 static Xen g_region_graph_style(void) {return(C_int_to_Xen_integer(region_graph_style(ss)));}
2251
g_set_region_graph_style(Xen val)2252 static Xen g_set_region_graph_style(Xen val)
2253 {
2254 int style;
2255 #define H_region_graph_style "(" S_region_graph_style "): graph style of the region dialog graph. \
2256 The " S_region_graph_style " choices are " S_graph_lines ", " S_graph_dots ", " S_graph_filled ", " S_graph_lollipops ", \
2257 and " S_graph_dots_and_lines "."
2258
2259 Xen_check_type(Xen_is_integer(val), val, 1, S_set S_region_graph_style, "an integer");
2260
2261 style = Xen_integer_to_C_int(val);
2262 if (!is_graph_style(style))
2263 Xen_out_of_range_error(S_set S_region_graph_style, 1, val, "unknown " S_lisp_graph_style);
2264
2265 set_region_graph_style((graph_style_t)style);
2266 reflect_region_graph_style();
2267 return(val);
2268 }
2269
2270
Xen_wrap_any_args(g_restore_region_w,g_restore_region)2271 Xen_wrap_any_args(g_restore_region_w, g_restore_region)
2272 Xen_wrap_4_optional_args(g_insert_region_w, g_insert_region)
2273 Xen_wrap_no_args(g_regions_w, g_regions)
2274 Xen_wrap_2_optional_args(g_region_framples_w, g_region_framples)
2275 Xen_wrap_2_optional_args(g_region_position_w, g_region_position)
2276 Xen_wrap_1_arg(g_region_srate_w, g_region_srate)
2277 Xen_wrap_1_arg(g_region_chans_w, g_region_chans)
2278 Xen_wrap_1_arg(g_region_home_w, g_region_home)
2279 Xen_wrap_1_arg(g_region_maxamp_w, g_region_maxamp)
2280 Xen_wrap_1_arg(g_region_maxamp_position_w, g_region_maxamp_position)
2281 Xen_wrap_1_arg(g_forget_region_w, g_forget_region)
2282 Xen_wrap_4_optional_args(g_make_region_w, g_make_region)
2283 Xen_wrap_5_optional_args(g_mix_region_w, g_mix_region)
2284 Xen_wrap_3_optional_args(g_region_sample_w, g_region_sample)
2285 Xen_wrap_5_optional_args(g_region_to_vct_w, g_region_to_vct)
2286 Xen_wrap_1_arg(g_is_region_w, g_is_region)
2287 Xen_wrap_no_args(g_max_regions_w, g_max_regions)
2288 Xen_wrap_1_arg(g_set_max_regions_w, g_set_max_regions)
2289 Xen_wrap_no_args(g_region_graph_style_w, g_region_graph_style)
2290 Xen_wrap_1_arg(g_set_region_graph_style_w, g_set_region_graph_style)
2291 Xen_wrap_1_arg(g_integer_to_region_w, g_integer_to_region)
2292 Xen_wrap_1_arg(g_region_to_integer_w, g_region_to_integer)
2293
2294 #if HAVE_SCHEME
2295 static s7_pointer acc_region_graph_style(s7_scheme *sc, s7_pointer args) {return(g_set_region_graph_style(s7_cadr(args)));}
acc_max_regions(s7_scheme * sc,s7_pointer args)2296 static s7_pointer acc_max_regions(s7_scheme *sc, s7_pointer args) {return(g_set_max_regions(s7_cadr(args)));}
2297 #else
2298 Xen_wrap_9_optional_args(g_save_region_w, g_save_region)
2299 #endif
2300
2301
g_init_regions(void)2302 void g_init_regions(void)
2303 {
2304 #if HAVE_SCHEME
2305 s7_pointer i, b, p, t, r, f, s, fv, rg;
2306 i = s7_make_symbol(s7, "integer?");
2307 rg = s7_make_symbol(s7, "region?");
2308 b = s7_make_symbol(s7, "boolean?");
2309 p = s7_make_symbol(s7, "list?");
2310 f = s7_make_symbol(s7, "float?");
2311 r = s7_make_symbol(s7, "real?");
2312 s = s7_make_symbol(s7, "string?");
2313 fv = s7_make_symbol(s7, "float-vector?");
2314 t = s7_t(s7);
2315 #endif
2316
2317 init_xen_region();
2318 #if (!HAVE_SCHEME)
2319 init_region_keywords();
2320 #endif
2321
2322 Xen_define_typed_procedure(S_restore_region, g_restore_region_w, 0, 0, 1, "internal func used in save-state, restores a region",
2323 s7_make_signature(s7, 11, i, i, i, i, i, r, s, s, s, s, p));
2324 Xen_define_typed_procedure(S_insert_region, g_insert_region_w, 2, 2, 0, H_insert_region, s7_make_signature(s7, 5, rg, rg, i, t, t));
2325 Xen_define_typed_procedure(S_forget_region, g_forget_region_w, 1, 0, 0, H_forget_region, s7_make_signature(s7, 2, rg, rg));
2326 Xen_define_typed_procedure(S_make_region, g_make_region_w, 0, 4, 0, H_make_region, s7_make_signature(s7, 5, rg, i, i, t, t));
2327 Xen_define_typed_procedure(S_mix_region, g_mix_region_w, 1, 4, 0, H_mix_region, s7_make_signature(s7, 6, t, rg, i, t, t, t));
2328
2329 Xen_define_typed_procedure(S_regions, g_regions_w, 0, 0, 0, H_regions, s7_make_signature(s7, 1, p));
2330 Xen_define_typed_procedure(S_region_framples, g_region_framples_w, 1, 1, 0, H_region_framples, s7_make_signature(s7, 3, i, rg, i));
2331 Xen_define_typed_procedure(S_region_position, g_region_position_w, 1, 1, 0, H_region_position, s7_make_signature(s7, 3, i, rg, i));
2332 Xen_define_typed_procedure(S_region_srate, g_region_srate_w, 1, 0, 0, H_region_srate, s7_make_signature(s7, 2, i, rg));
2333 Xen_define_typed_procedure(S_region_chans, g_region_chans_w, 1, 0, 0, H_region_chans, s7_make_signature(s7, 2, i, rg));
2334 Xen_define_typed_procedure(S_region_home, g_region_home_w, 1, 0, 0, H_region_home, s7_make_signature(s7, 2, p, rg));
2335 Xen_define_typed_procedure(S_region_maxamp, g_region_maxamp_w, 1, 0, 0, H_region_maxamp, s7_make_signature(s7, 2, f, rg));
2336 Xen_define_typed_procedure(S_region_maxamp_position, g_region_maxamp_position_w, 1, 0, 0, H_region_maxamp_position, s7_make_signature(s7, 2, i, rg));
2337 Xen_define_typed_procedure(S_region_sample, g_region_sample_w, 2, 1, 0, H_region_sample, s7_make_signature(s7, 4, f, rg, i, i));
2338 Xen_define_typed_procedure(S_region_to_vct, g_region_to_vct_w, 1, 4, 0, H_region_to_vct, s7_make_signature(s7, 6, fv, rg, i, i, i, fv));
2339 Xen_define_typed_procedure(S_is_region, g_is_region_w, 1, 0, 0, H_is_region, s7_make_signature(s7, 2, b, t));
2340
2341 Xen_define_typed_procedure(S_integer_to_region, g_integer_to_region_w, 1, 0, 0, H_integer_to_region, s7_make_signature(s7, 2, rg, i));
2342 Xen_define_typed_procedure(S_region_to_integer, g_region_to_integer_w, 1, 0, 0, H_region_to_integer, s7_make_signature(s7, 2, i, rg));
2343
2344 Xen_define_typed_dilambda(S_max_regions, g_max_regions_w, H_max_regions, S_set S_max_regions, g_set_max_regions_w, 0, 0, 1, 0,
2345 s7_make_signature(s7, 1, i), s7_make_signature(s7, 2, i, i));
2346
2347 Xen_define_typed_dilambda(S_region_graph_style, g_region_graph_style_w, H_region_graph_style,
2348 S_set S_region_graph_style, g_set_region_graph_style_w, 0, 0, 1, 0,
2349 s7_make_signature(s7, 1, i), s7_make_signature(s7, 2, i, i));
2350
2351 #if HAVE_SCHEME
2352 s7_set_setter(s7, ss->max_regions_symbol, s7_make_function(s7, "[acc-" S_max_regions "]", acc_max_regions, 2, 0, false, "accessor"));
2353 s7_set_setter(s7, ss->region_graph_style_symbol, s7_make_function(s7, "[acc-" S_region_graph_style "]", acc_region_graph_style, 2, 0, false, "accessor"));
2354
2355 s7_set_documentation(s7, ss->max_regions_symbol, "*max-regions*: max number of regions saved on the region list");
2356 s7_set_documentation(s7, ss->region_graph_style_symbol, "*region-graph-style*: graph style of the region dialog graph (graph-lines etc)");
2357
2358 s7_define_safe_function_star(s7, S_save_region, g_save_region, "region file sample-type header-type comment", H_save_region);
2359 #else
2360 Xen_define_typed_procedure(S_save_region, g_save_region_w, 2, 7, 0, H_save_region, s7_make_circular_signature(s7, 0, 1, t));
2361 #endif
2362 }
2363
2364