(SIOSC-ALG (NAME "siosc") ; wave tables are provided in the argument "lis" as follows: ; (tab0 t1 tab1 t2 tab2 t3 tab3 ... tN tabN) ; where tab0 is the initial table, the table is linearly interpolated until ; sample t1, at which point the table is tab1. From there, tab1 is interpolated ; to tab2 at t2, etc. The sound stops at the terminate time of s_fm, so ; if that comes before tN, tabN is used for the remainder of the sound. ; t1, t2, ... tN are fixnums with sample counts (ARGUMENTS ("LVAL" "lis") ("rate_type" "sr") ("double" "hz") ("time_type" "t0") ("sound_type" "s_fm")) (SUPPORT-FUNCTIONS " /* sisosc_table_init -- set up first two tables for interpolation */ /**/ void siosc_table_init(siosc_susp_type susp) { sound_type snd; if (!susp->lis) xlfail(\"bad table list in SIOSC\"); snd = getsound(car(susp->lis)); susp->table_b_ptr_ptr = sound_to_table(snd); susp->table_b_samps = susp->table_b_ptr_ptr->samples; susp->lis = cdr(susp->lis); susp->table_sr = snd->sr; susp->table_len = susp->table_b_ptr_ptr->length; } /* siosc_table_update -- outer loop processing, get next table */ /**/ long siosc_table_update(siosc_susp_type susp, long cur) { long n; /* swap ampramps: */ susp->ampramp_a = 1.0; susp->ampramp_b = 0.0; /* swap tables: */ table_unref(susp->table_a_ptr); susp->table_a_ptr = susp->table_b_ptr_ptr; susp->table_a_samps = susp->table_b_samps; susp->table_b_ptr_ptr = NULL; /* so we do not try to unref it */ if (susp->lis) { sound_type snd; /* compute slope */ susp->next_breakpoint = getfixnum(car(susp->lis)); susp->lis = cdr(susp->lis); n = susp->next_breakpoint - cur; susp->ampslope = 1.0 / n; /* build new table: */ if (!susp->lis) xlfail(\"bad table list in SIOSC\"); snd = getsound(car(susp->lis)); susp->table_b_ptr_ptr = sound_to_table(snd); susp->table_b_samps = susp->table_b_ptr_ptr->samples; if (susp->table_b_ptr_ptr->length != susp->table_len || susp->table_sr != snd->sr) xlfail(\"mismatched tables passed to SIOSC\") ; susp->lis = cdr(susp->lis); } else { /* use only table a */ susp->ampslope = 0.0; susp->next_breakpoint = 0x7FFFFFFF; n = 0x7FFFFFFF; } return n; } ") (STATE ("double" "table_len" "0.0") ("double" "ph_incr" "0.0") ("table_type" "table_a_ptr" "NULL") ("table_type" "table_b_ptr_ptr" "NULL") ("sample_type *" "table_a_samps" "NULL") ("sample_type *" "table_b_samps" "NULL") ("double" "table_sr" "0.0") ("double" "phase" "0.0") ("LVAL" "lis" "lis") ("long" "next_breakpoint" "0") ("double" "ampramp_a" "1.0") ("double" "ampramp_b" "0.0") ("double" "ampslope" "0.0; siosc_table_init(susp); susp->ph_incr = hz * susp->table_len / sr; s_fm->scale = (sample_type) (s_fm->scale * (susp->table_len / sr))") ) (ALWAYS-SCALE s_fm) (INLINE-INTERPOLATION T) ; so that modulation can be low frequency (STEP-FUNCTION s_fm) (TERMINATE (MIN s_fm)) (LOGICAL-STOP (MIN s_fm)) (INNER-LOOP-LOCALS " long table_index; double xa, xb; ") ; Implementation notes: ; "lis" points to the next time to be used, or NULL (OUTER-LOOP " { long cur = susp->susp.current + cnt; n = susp->next_breakpoint - cur; if (n == 0) n = siosc_table_update(susp, cur); } togo = min(n, togo); ") (INNER-LOOP " table_index = (long) phase; xa = table_a_samps[table_index]; xb = table_b_samps[table_index]; output = (sample_type) (ampramp_a * (xa + (phase - table_index) * (table_a_samps[table_index + 1] - xa)) + ampramp_b * (xb + (phase - table_index) * (table_b_samps[table_index + 1] - xb))); ampramp_a -= ampslope; ampramp_b += ampslope; phase += ph_incr + s_fm; while (phase > table_len) phase -= table_len; /* watch out for negative frequencies! */ while (phase < 0) phase += table_len") (CONSTANT "ph_incr" "table_len" "table_ptr" "table_a_samps" "table_b_samps" "ampslope" "table_a_ptr" "table_b_ptr_ptr") (SAMPLE-RATE "sr") (FINALIZATION " table_unref(susp->table_a_ptr); table_unref(susp->table_b_ptr_ptr); ") )