📄 add.c
字号:
/* add.c -- add two signals *//* CHANGE LOG * 19May92 rbd fix t0 to mean time rather than samples fix to logically stop and terminate at MAX of 2 inputs * 28Apr03 dm changes for portability and fix compiler warnings *//* DOCUMENTATION: Most DSP modules in Nyquist select a single fetch routineand use it until the signal terminates. The ADD operationinstead can use a number of different fetch routines in sequence.This allows ADD to do the most efficient computation, such assimply copying pointers when only one input signal is defined(the other is zero.) Here's what the functions assume and do:add_s1_s2_nn_fetch: both arguments (s1, s2) have signals; add them.add_s1_nn_fetch: only s1 is active, so pass along pointers if possible. Revert to add_s1_s2_nn_fetch when s2 becomes active.add_s2_nn_fetch: symetric with add_s1_nn_fetch.add_zero_fill_nn_fetch: fill in when one input has terminated and the other hasn't begun.An important optimization (we think) is the ability to collapseADD operations. When one operand goes to zero, the ADD justpasses along pointers to blocks from the other operand. In somecases, we can just splice out the ADD suspension and linkdirectly to the suspension of the second operand.Doing this requires that there be no scale factors, so ADD doesnot deal with scaling. If an operand comes in with a scalefactor, ADD will create a rescaling of the operand.*/#include "switches.h"#include "stdio.h"#ifndef mips#include "stdlib.h"#endif#include "xlisp.h"#include "sound.h"#include "falloc.h"#include "cext.h"#include "scale.h"#include "multiseq.h"#include "add.h"#define debugA 0#define A if (debugA)/* I don't know how these debug switches (A and D) differ: */#define D A/* switch B is/was to look for a particular zero block length bug */#define debugB 0#define B if (debugB | debugA) /* #define GC_DEBUG 1 */void add_s1_s2_nn_fetch(add_susp_type, snd_list_type);void add_s1_nn_fetch(add_susp_type, snd_list_type);void add_s2_nn_fetch(add_susp_type, snd_list_type);void add_zero_fill_nn_fetch(add_susp_type, snd_list_type);void add_free();void add_s1_s2_nn_fetch(susp, snd_list) register add_susp_type susp; snd_list_type snd_list;{ int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type s1_ptr_reg; register sample_block_values_type s2_ptr_reg; register sample_block_values_type out_ptr_reg;#ifdef GC_DEBUG snd_list_report(snd_list, "add_s1_s2_nn_fetch");#endif /* assume the snd_list is the one with a null block */ /* put a fresh, clean block in the snd_list (get new snd_list later) */ falloc_sample_block(out, "add_s1_s2_nn_fetch"); snd_list->block = out; out_ptr = out->samples;A nyquist_printf("add[%p,%p] (s1_s2_nn) %p new block %p\n", susp->s1, susp->s2, susp, out); /* fill up the new block */ while (cnt < max_sample_block_len && susp->terminate_bits == 0) {A nyquist_printf("add[%p,%p] (s1_s2_nn) %p starting outer loop, cnt %d\n", susp->s1, susp->s2, susp, cnt); /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */A nyquist_printf("add[%p,%p]: look for samples (for s1) \n", susp->s1, susp->s2);/* if (!susp->s1->list->block) watch_susp(susp->s1->list->u.susp); */ susp_check_term_log_block_samples(s1, s1_bptr, s1_ptr, s1_cnt, 1, 3);A nyquist_printf("add[%p,%p]: found samples (for s1) s1_cnt=%d\n", susp->s1, susp->s2, (int)susp->s1_cnt); togo = MIN(togo, susp->s1_cnt); if (susp->terminate_bits & 1) {A nyquist_printf("add[%p,%p]: terminate bits on (for s1) togo=%d\n", susp->s1, susp->s2, togo); } /* don't run past the s2 input sample block: */A nyquist_printf("add[%p,%p]: look for samples (for s2) \n", susp->s1, susp->s2); susp_check_term_log_block_samples(s2, s2_bptr, s2_ptr, s2_cnt, 2, 3);A nyquist_printf("add[%p,%p]: found samples (for s2) s2_cnt=%d\n", susp->s1, susp->s2, (int)susp->s2_cnt); togo = MIN(togo, susp->s2_cnt);A if (susp->terminate_bits & 2) { nyquist_printf("add[%p,%p]: terminate bits on (for s2) togo=%d\n", susp->s1, susp->s2, togo); } /* don't run past logical stop time (need to check this even * if a sound has terminated) */A nyquist_printf( "add[%p,%p] (s1_s2_nn) %p: logically_stopped %d, logical_stop_cnt %d\n", susp->s1, susp->s2, susp, susp->logically_stopped, (int)susp->susp.log_stop_cnt); if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt);A nyquist_printf("add[%p,%p]: to_stop = %d\n", susp->s1, susp->s2, to_stop); /* logical stops have to be indicated on block boundaries */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* indicate logical stop immediately */ susp->logically_stopped = true; } else { /* logical stop will take place on the following block, * so compute up to logical stop and return partial block */ togo = to_stop; } } } /* check please */ if (susp->terminate_bits) { break; } /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt);D nyquist_printf("add[%p,%p]: togo = %d\n", susp->s1, susp->s2, togo); if (togo == 0) break; } n = togo;A nyquist_printf("add[%p,%p] (s1_s2_nn) %p starting inner loop, n %d\n", susp->s1, susp->s2, susp, n); s1_ptr_reg = susp->s1_ptr; s2_ptr_reg = susp->s2_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ /* scale? */A nyquist_printf("add_s1_s2_nn: %g + %g\n", *s1_ptr_reg, *s2_ptr_reg); *out_ptr_reg++ = *(s1_ptr_reg++) + *(s2_ptr_reg++); } while (--n); /* inner loop */ /* using s1_ptr_reg is a bad idea on RS/6000 */ susp->s1_ptr += togo; /* using s2_ptr_reg is a bad idea on RS/6000 */ susp->s2_ptr += togo; /* using out_ptr_reg is a bad idea on RS/6000 */ out_ptr += togo; susp_took(s1_cnt, togo); susp_took(s2_cnt, togo); cnt += togo; } /* outer loop */ A nyquist_printf("add[%p,%p] (s1_s2_nn) %p ending outer loop, cnt %d\n", susp->s1, susp->s2, susp, cnt); snd_list->block_len = cnt; /* test for logical stop - normally this is detected by * susp.log_stop_cnt == susp->susp.current, but then the logical * stop flag is set on the NEXT block. To remember to set on the * NEXT block, set susp->logically_stopped, which is also tested * below. One special case is if the current block should indicate * logically stopped (this happens sometimes when the sounds have * zero logical length) then susp->logically_stopped will be set * (see above) and we just never test susp->susp.log_stop_cnt. */ if (susp->logically_stopped) {A nyquist_printf("add[%p,%p] (s1_s2_nn) %p->logically_stopped already true\n", susp->s1, susp->s2, susp); snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) {A nyquist_printf("add[%p,%p] (s1_s2_nn) %p->logically_stopped set to true\n", susp->s1, susp->s2, susp); susp->logically_stopped = true; } /* test for termination of s1 */ if (susp->terminate_bits == 3) {D nyquist_printf("add[%p,%p] (s1_s2_nn) s1 and s2 terminated, unrefed\n", susp->s1, susp->s2); /* free susp and point to terminal zeros (leaving pending snd_lists)*/ if (cnt) { /* we have samples, put zero_block at end */ snd_list_unref(snd_list->u.next); snd_list->u.next = zero_snd_list; } else { /* no samples generated */ snd_list_terminate(snd_list); }D nyquist_printf("add[%p,%p] (s1_s2_nn) %p terminated.\n", susp->s1, susp->s2, susp); } else { if (susp->terminate_bits & 1) {D nyquist_printf("add[%p,%p] (s1_s2_nn) s1 terminated, unrefed\n", susp->s1, susp->s2); sound_unref(susp->s1); susp->s1 = NULL; susp->susp.fetch = add_s2_nn_fetch;D nyquist_printf("add_s1_s2_nn_fetch: add_s2_nn_fetch installed\n"); if (cnt == 0) {D nyquist_printf("add[%p,%p]: calling add_s2_nn_fetch\n", susp->s1, susp->s2); add_s2_nn_fetch(susp, snd_list); } } else if (susp->terminate_bits & 2) {D nyquist_printf("add[%p,%p] (s1_s2_nn) s2 terminated, unrefed\n", susp->s1, susp->s2); sound_unref(susp->s2); susp->s2 = NULL; susp->susp.fetch = add_s1_nn_fetch;D stdputstr("add_s1_s2_nn_fetch: add_s1_nn_fetch installed\n"); if (cnt == 0) {D nyquist_printf("add[%p,%p]: calling add_s1_nn_fetch\n", susp->s1, susp->s2); add_s1_nn_fetch(susp, snd_list); } } /* add a new snd_list for the susp */ susp->susp.current += cnt; }} /* add_s1_s2_nn_fetch *//* Note that add_s1_nn_fetch and add_s2_nn_fetch are symetric. * They should probably be made into one routine, but for now, * any changes to one should be made to the other. */void add_s1_nn_fetch(susp, snd_list) register add_susp_type susp; snd_list_type snd_list;{ /* expansion of add_s_nn_fetch(snd_list,s1,s2,1); follows: */ int togo, s2_start=0; int n; sample_block_type out; register sample_block_values_type out_ptr;D nyquist_printf("add_s1_nn_fetch(susp %p, snd_list %p, s1_cnt %d)\n", susp, snd_list, (int)susp->s1_cnt);#ifdef GC_DEBUG snd_list_report(snd_list, "add_s1_nn_fetch");#endif /* * first compute how many samples to copy (or transfer) */ /* see what the next samples look like */ susp_check_term_log_block_samples(s1, s1_bptr, s1_ptr, s1_cnt, 1, 3);B if (susp->terminate_bits & 1) nyquist_printf("add[%p,%p]: s1 terminates\n", susp->s1, susp->s2); /* don't run past the s1 input sample block: */ togo = susp->s1_cnt;B if (togo == 0) stdputstr("togo is zero at checkpoint 1\n"); /* don't run past terminate time of this signal */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -