📄 multiseq.c
字号:
} else xlerror("closure did not return a sound", result); /* now result holds a vector of nchans, insert them into add_susp's */ for (i = 0; i < ms->nchans; i++) { snd_list_type snd_list = ms->chans[i]; add_susp_type susp = (add_susp_type) snd_list->u.susp; long sother_start; /* remove backpointer to ms */ susp->multiseq = NULL; susp->susp.print_tree = add_print_tree; susp->susp.free = add_free; susp->susp.mark = add_mark; susp->s2 = sound_copy(getsound(getelement(result, i))); if (susp->s1->sr != susp->s2->sr) xlfail("multiseq: sample rates must match"); if (susp->s2->scale != 1.0) { susp->s2 = snd_make_normalize(susp->s2); } sother_start = ROUND((susp->s2->t0 - susp->susp.t0) * susp->s2->sr);D nyquist_printf("sother_start computed for %p: %d\n", susp, (int)sother_start); if (sother_start > susp->susp.current) {D nyquist_printf("susp %p using add_s1_nn_fetch\n", susp); susp->susp.fetch = add_s1_nn_fetch; susp->susp.name = "multiseq:add_s1_nn_fetch"; } else if (susp->terminate_bits) { /* s1 is done, just get s2 now */ sound_unref(susp->s1); susp->s1 = NULL;D nyquist_printf("susp %p using add_s2_nn_fetch\n", susp); susp->susp.fetch = add_s2_nn_fetch; susp->susp.name = "multiseq:add_s2_nn_fetch"; } else {D nyquist_printf("susp %p using add_s1_s2_nn_fetch\n", susp); susp->susp.fetch = add_s1_s2_nn_fetch; susp->susp.name = "multiseq:add_s1_s2_nn_fetch"; } /* fix up logical stop info */ /* BUG: what if s2 is already stopped? */ susp->susp.log_stop_cnt = UNKNOWN; susp->logically_stopped = false; /* we need to compute at least 1 sample * (at this point we don't really know if we've * computed anything or not, so to be safe, do it. */ snd_list->u.next = snd_list_create(&(susp->susp)); snd_list->block = internal_zero_block; (*(susp->susp.fetch))(susp, snd_list); } /* now free the multiseq struct */ size = sizeof(snd_list_type) * ms->nchans; ffree_generic(ms->chans, size, "multiseq_convert"); ffree_generic(ms, sizeof(multiseq_node), "multiseq_convert(2)"); ms->closure = NIL; /* allow garbage collection now */ xlpop();}/* multiseq_fetch returns blocks of s1 until the logical stop time of s1's *//* * Fetch routines (in particular, the add_*_fetch routines that will * be installed on this susp at a later time) expect to be called with * a new snd_list installed and ready for a new block. However, since * we are going to call multiseq_advance to pull blocks out of susps * that will not be set up with a fresh snd_list in this way, it is * simpler to dispose of the preallocated snd_list so that all susps * look alike to multiseq_advance. Of course, multiseq_advance will * redo the work of allocating a snd_list. * * If a channel terminates early, we must be careful: continuing to * fetch will return pointers to the zero_block, but this will * indicate termination to whoever is fetching from multiseq. We * must check the pointers and substitute internal_zero_block to * avoid premature termination. */void multiseq_fetch(susp, snd_list) register add_susp_type susp; snd_list_type snd_list;{ time_type block_end_time; /* undo the preallocation of a snd_list_node */ /* we can bypass the reference counting code because we * know that this snd_list was just allocated and has no * other references */#ifdef MULTISEQ_GC_DEBUG if (snd_list_to_watch == snd_list->u.next) { nyquist_printf("multiseq_fetch: backing out snd_list_to_watch from %p\n", snd_list_to_watch); watch_snd_list(snd_list); }#endif ffree_snd_list(snd_list->u.next, "multiseq_fetch"); snd_list->u.susp = (snd_susp_type) susp; snd_list->block = NULL;D nyquist_printf("multiseq_fetch called: susp %p s1_cnt %d\n", susp, (int)susp->s1_cnt); /* first compute how many samples we can generate from s1: */ if (susp->s1_cnt == 0) { susp_get_block_samples(s1, s1_bptr, s1_ptr, s1_cnt); if (susp->s1_ptr == zero_block->samples) { susp->terminate_bits = 1; /* mark s1 as terminated */ susp->s1_bptr = internal_zero_block; susp->s1_ptr = internal_zero_block->samples; } /* see if we've reached a logical stop * (I can't believe this code block is in 3 places - * there must be a better way... RBD) */ if (!susp->logical_stop_bits) { if (susp->s1->logical_stop_cnt != UNKNOWN) { if (susp->susp.current + susp->s1_cnt >= susp->s1->logical_stop_cnt) { susp->logical_stop_bits = 1; susp->susp.log_stop_cnt = susp->s1->logical_stop_cnt; susp->multiseq->not_logically_stopped_cnt--;D nyquist_printf( "snd_make_multiseq: Logical stop reached, not_logically_stopped_cnt %d\n", susp->multiseq->not_logically_stopped_cnt); } } } } /* s1_cnt has the number of samples we can return */ /* now compute time of the last sample */ block_end_time = susp_time(susp, susp->multiseq);D nyquist_printf("block_end_time of %p: %g\n", susp, block_end_time); multiseq_advance(susp->multiseq, block_end_time);}/* multiseq_mark -- mark routine for multiseq susps *//**/void multiseq_mark(add_susp_type susp){ int i; multiseq_type ms = susp->multiseq;D nyquist_printf("multiseq_mark(%p)\n", susp);/* nyquist_printf("marking s1@%p in add@%p\n", susp->s1, susp);*/ if (ms->closure) mark(ms->closure); /* mark s1 of each susp in multiseq */ for (i = 0; i < ms->nchans; i++) { snd_list_type snd_list = ms->chans[i]; if (snd_list) { while (snd_list->block != NULL) { if (snd_list == zero_snd_list) break; snd_list = snd_list->u.next; } sound_xlmark(((add_susp_type) snd_list->u.susp)->s1); } }}/* snd_make_multiseq -- make a multiseq from an array and a closure *//* * NOTE: the resulting array of sounds will not use the normal * SND_get_first and SND_get_next routines to fetch new blocks * because these extend the snd_list of the sound immediately, * and this would confuse multiseq_advance() which has to extend * multiple snd_lists synchronously. So, we use multiseq_get_next() * instead. */LVAL snd_make_multiseq(LVAL s1, LVAL closure){ multiseq_type ms; int i; LVAL result; xlsave1(result); /* allocate multiseq */ falloc_generic(ms, multiseq_node, "snd_make_multiseq"); /* install its array of snd_list_type */ if (!vectorp(s1) || getsize(s1) == 0) { ffree_generic(ms, sizeof(multiseq_node), "snd_make_multiseq"); xlerror("bad argument type", s1); } ms->nchans = getsize(s1); ms->closure = closure; ms->not_logically_stopped_cnt = 0; ms->low_water = 0.0; ms->horizon = 0.0; falloc_generic_n(ms->chans, snd_list_type, ms->nchans, "snd_make_multiseq"); /* allocate sounds to return */ result = newvector(ms->nchans); /* ms->t0 will be the minimum of all t0's in array */ ms->t0 = (getsound(getelement(s1, 0)))->t0; /* create sounds to return */ for (i = 0; i < ms->nchans; i++) { add_susp_type susp; sound_type snd; falloc_generic(susp, add_susp_node, "snd_make_multiseq(add_susp)"); susp->s1 = sound_copy(getsound(getelement(s1, i))); /* we used to only incr this if lsc was UNKNOWN, but that's wrong. Should move this out of the loop now. */ if (susp->s1->scale != 1.0) { /* stdputstr("normalizing first sound in a seq\n"); */ susp->s1 = snd_make_normalize(susp->s1); } ms->not_logically_stopped_cnt++;D nyquist_printf("snd_make_multiseq: not_logically_stopped_cnt %d\n", ms->not_logically_stopped_cnt); susp->s1_cnt = 0; susp->s2 = NULL; susp->s2_cnt = 0; susp->susp.fetch = multiseq_fetch; susp->susp.free = multiseq_free; susp->susp.sr = susp->s1->sr; susp->susp.mark = multiseq_mark; susp->susp.print_tree = multiseq_print_tree; susp->susp.name = "multiseq"; susp->susp.t0 = susp->s1->t0; susp->terminate_bits = 0; /* bits for s1 and s2 termination */ susp->terminate_cnt = UNKNOWN; susp->logical_stop_bits = 0; /* bits for s1 and s2 log. stop */ susp->susp.log_stop_cnt = UNKNOWN; susp->logically_stopped = false; susp->started = false; susp->susp.current = 0; susp->multiseq = ms; snd = sound_create((snd_susp_type) susp, susp->s1->t0, susp->susp.sr, 1.0);#ifdef GC_DEBUG if (snd == sound_to_watch) { nyquist_printf("watched sound is channel %d\n", i); }#endif setelement(result, i, cvsound(snd)); if (snd->list->block || !snd->list->u.susp) { stdputstr("data inconsistency in snd_make_seq\n"); EXIT(1); } ms->chans[i] = snd->list;D nyquist_printf("ms->chans[%d] = %p, %p->u.susp = %p\n", i, snd->list, snd->list, snd->list->u.susp); ms->t0 = MIN(ms->t0, susp->s1->t0); ms->sr = susp->s1->sr; /* assume all samp rates are equal */D nyquist_printf("Multiseq sound[%d]: \n", i);D sound_print_tree(susp->s1); }D nyquist_printf("ms->t0 == %g\n", ms->t0); xlpop(); return result;}/* note: snd_multiseq is a noop, just call snd_make_multiseq */void multiseq_free(add_susp_type susp){ int i; multiseq_type ms = susp->multiseq; boolean dead = true; sound_unref(susp->s1); sound_unref(susp->s2); /* probably not necessary */ /* tricky part: remove pointer from ms->chans */ for (i = 0; i < ms->nchans; i++) { if (ms->chans[i]) { dead = false; /* * note that ms->chans is still a valid * pointer (see snd_list_unref) */ if (ms->chans[i]->u.susp == (snd_susp_type) susp) { ms->chans[i] = NULL;D nyquist_printf("susp %p freed, ms@%p->chans[%d] = NULL\n", susp, ms, i); } } } /* if last element is freed, free the multiseq struct too */ if (dead) { i = sizeof(snd_list_type) * ms->nchans; ffree_generic(ms->chans, i, "multiseq_free"); ffree_generic(ms, sizeof(multiseq_node), "multiseq_free(2)"); } susp->multiseq = NULL; /* just to be safe */ ffree_generic(susp, sizeof(add_susp_node), "multiseq_free(3)");}void multiseq_print_tree(add_susp_type susp, int n){ int i; indent(n); if (!susp->multiseq) { xlfail("internal error: missing multiseq structure"); } nyquist_printf("multiseq@%p = [ ", susp->multiseq); for (i = 0; i < susp->multiseq->nchans; i++) { if (susp->multiseq->chans[i]) { nyquist_printf("%p", susp->multiseq->chans[i]->u.susp); } else { stdputstr("NULL"); } } indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("closure:"); stdprint(susp->multiseq->closure); indent(n);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -