diff options
Diffstat (limited to 'tran/alpassvc.alg')
-rw-r--r-- | tran/alpassvc.alg | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/tran/alpassvc.alg b/tran/alpassvc.alg new file mode 100644 index 0000000..c3c13db --- /dev/null +++ b/tran/alpassvc.alg @@ -0,0 +1,59 @@ +(ALPASSVC-ALG +;; +;; delay is variable -- but we don't want to reallocate the delay buffer, so +;; use an additional parameter for the maximum allowable delay. The sound will +;; be written into the buffer every sample, but read using linear +;; interpolation. As in tapv, duplicate the sample at the first and last +;; locations in the buffer. +;; +(NAME "alpassvc") +(ARGUMENTS ("sound_type" "input") ("sound_type" "delaysnd") ("double" "feedback") + ("double" "maxdelay")) +(START (MAX input delaysnd)) +(STATE ("float" "delay_scale_factor" "(float) (input->sr * delaysnd->scale)") + ("double" "feedback" "feedback") + ("long" "buflen" "max(2, (long) (input->sr * maxdelay + 2.5))") + ("sample_type *" "delaybuf" + "(sample_type *) calloc (susp->buflen + 1, sizeof(sample_type))") + ("sample_type *" "delayptr" "susp->delaybuf") +;; since we allocate one extra sample, endptr points to the last sample + ("sample_type *" "endptr" "susp->delaybuf + susp->buflen")) +(CONSTANT "feedback" "delaylen" "endptr" "delay_scale_factor") +(NOT-REGISTER delaybuf) +(LINEAR input) +(TERMINATE (MIN input)) +(INNER-LOOP-LOCALS " register sample_type y, z, delaysamp; + register int delayi; + register sample_type *yptr;\n") +(INNER-LOOP " + /* compute where to read y, we want y to be delay_snd samples + * after delay_ptr, where we write the new sample. First, + * conver from seconds to samples. Note: don't use actual sound_type + * names in comments! The translator isn't smart enough. + */ + delaysamp = delaysnd * delay_scale_factor; + delayi = (int) delaysamp; /* get integer part */ + delaysamp = delaysamp - delayi; /* get phase */ + yptr = delayptr + buflen - (delayi + 1); + if (yptr >= endptr) yptr -= buflen; + /* now get y, the out-put of the delay, using interpolation */ + /* note that as phase increases, we use more of yptr[0] because + positive phase means longer buffer means read earlier sample */ + y = (float) ((yptr[0] * delaysamp) + (yptr[1] * (1.0 - delaysamp))); + /* WARNING: no check to keep delaysamp in range, so do this in LISP */ + + *delayptr++ = z = (sample_type) (feedback * y + input); + /* Time out to update the buffer: + * this is a tricky buffer: buffer[0] == buffer[bufflen] + * the logical length is bufflen, but the actual length + * is bufflen + 1 to allow for a repeated sample at the + * end. This allows for efficient interpolation. + */ + if (delayptr > endptr) { + delayptr = susp->delaybuf; + *delayptr++ = *endptr; + } + output = (sample_type) (y - feedback * z);") +(FINALIZATION "free(susp->delaybuf);") +) + |