Variable Delay Line in C
Date | 2016-04-24 17:20 |
From | Emmett Palaima |
Subject | Variable Delay Line in C |
Hi, I am working on programming a variable delay line in C for a school project, and was looking at examples from the Audio Programming Book (P.495-496) and from Csound's vdelay opcode to base my work off of. I analyzed these and built my own model (inside a larger program, cModular by Tim Lukens), which is not yet functioning and still causes a large amount of distortion. I have a couple questions based on studying the examples, as well as line by line analysis of what I think the example code is doing, please let me know if you can answer some of these questions or point out any fallacies in my reasoning. Thanks!
Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here
The two programs seem to be doing the following: -Setting an input buffer to current input -Calculating delay index based on formula: delayIndex = currentIndex - delayTimeInSamples -Calculating adjacent delay index as an integer and fraction between the two -Sets output via formula: output = sampleFromIntegerIndex + (fractionAboveInteger * (sampleFromNextIntegerIndex)) -It seems that the main difference between these programs and my own is the presence of a loop based on vecsize (nsmps in Csound), a concept I do not fully understand. It seems like this is setting up an i/O buffer of vecsize samples, but this is handled elsewhere in cModular, and its in-built fixed delay does not have anything like this. Could this be what is causing the problem? Other things I am unclear on: -How long is the delayBuffer (is it MAX_DELAY?) -Interpolation here does not seem to solve the essential issue, that being that variable delay causes the delayIndex to jump around inside the buffer, leading to abrupt jumps in value -All the interpolation seems to be doing is dealing with a fractional delay samples value, which could have happened in an ordinary delay whether or not the value is changing -It seems like bufferSize is set to maxDelay, and index loops around when it reaches maxDelay time. I do not understand how this works with feedback. It seems like some of the feedback would get lost as the delay time changed, as would many of the input samples. Here is my analysis of the programs: //audio programming book float vdelay(float *sig, float vdtime, float maxdel, float *delay, int *p, int vecsize, float sr){ int mdt, rpi; float out, rp, vdt, frac, next; vdt = vdtime * sr; //sets float vdt to number of samples vdtime (delay time in seconds) * sr (samples per second) mdt = maxdel * sr; //set float mdt to number of samples maxdel (maximum delay in seconds) * sr (samples per second) if(vdt > mdt) vdt = (float) mdt; //sets vdt (delay time) to mdt (max delay) if it goes over for(int i = 0; i < vecsize; i++){ //i/O buffer stuff rp = *p - vdt; //what is p? I think rp represents the buffer read index and p might point to the buffer array? rp = (rp >= 0 ? (rp < mdt ? rp : rp - mdt);//i think ? is a replacement for if? rpi = (int) rp; //casts rp (read index?) as integer to create fraction in next line frac = rp - rpi; //gets fractional value of read pointer to see if it needs interpolation next = (rpi != mdt-1 ? delay[rpi+1] : delay[0]); //^ if rpi is not the last stage of the buffer next stage is rpi + 1, //otherwise next stage is start of buffer out = delay[rpi] + frac*(next - delay[rpi]); //^ provides linear interpolation by taking: // (current buffer stage) + (fractional ammount over buffer stage) * (difference between current and next buffer stage) delay[*p] = sig[i]; //sets delay at time p (current time) to sig[i] (input buffer?) sig[i] = out; //sets sig[i] to delay signal for output *p = (*p != mdt ? *p+1 : 0) //if p has not reached the end of the buffer increment it to the beginning } return *sig; //returns output buffer } //csound vdelay opcode (krate) MYFLT fdel=*del; //sets delay to input value for (nn=offset; nn<nsmps; nn++) { //input buffer stuff MYFLT fv1, fv2; int32 v1, v2; buf[indx] = in[nn]; //sets buffer at index to input fv1 = indx - fdel * ESR; //sets variable to index - (delay value in samples) /* Make sure inside the buffer */ /* * See comment above--same fix applied here. heh 981101 */ //makes sure fv1 is not below zero or beyond max delay time while (UNLIKELY(fv1 < FL(0.0))) fv1 += (MYFLT)maxd; while (UNLIKELY(fv1 >= (MYFLT)maxd)) fv1 -= (MYFLT)maxd; if (LIKELY(fv1 < maxd - 1)) /* Find next sample for interpolation */ fv2 = fv1 + FL(1.0); else fv2 = FL(0.0); //find next sample for interpolation v1 = (int32)fv1; v2 = (int32)fv2; out[nn] = buf[v1] + (fv1 - v1) * ( buf[v2] - buf[v1]); //same linear interpolation between adjacent samples if (UNLIKELY(++indx == maxd)) indx = 0; //increments indexs |
Date | 2016-04-24 18:18 |
From | Paul Batchelor |
Subject | Re: Variable Delay Line in C |
To try to answer some questions and give you some hints. People who know better, please feel free to jump in and correct: - variable delays do need a "maximum delay" because your delay line will need to allocate that space before the plugin starts.If you're learning how to make a delay line, I would figure out how to do a static delay line first, as the interpolation makes things a little more complicated. A static feedback delay line was one of the first DSP effects I coded from scratch in C, and it was a great experience for me. For what it's worth, I actually ported Csound's vdelay3 to Soundpipe. It's been cleaned up and simplified, so it may be easier for you to read and study from: https://github.com/PaulBatchelor/Soundpipe/blob/master/modules/vdelay.c All the best, -P On Sun, Apr 24, 2016 at 9:20 AM, Emmett Palaima <epalaima@berklee.edu> wrote:
|
Date | 2016-04-24 20:55 |
From | Emmett Palaima |
Subject | Re: Variable Delay Line in C |
Thank you for your advice and for the example code. The main thing that I'm still confused on is the type of interpolation that all these examples use. To the best of my understanding what they are doing is taking a sample from the buffer based on the current delay value, then averaging it with the next sample in the buffer to smooth out fractional delay values. (e.g. out = delay[rpi] + frac*(next - delay[rpi]);) The confusing thing about this is that it seems it would ONLY smooth out fractional delay values and wouldn't do anything to help smooth the jumps through the buffer index that the variable delay creates. If someone could explain how this works that would clear up a lot for me. Thanks! On Sun, Apr 24, 2016 at 1:18 PM, Paul Batchelor <ralphbluecoat@gmail.com> wrote:
|
Date | 2016-04-24 21:50 |
From | jpff |
Subject | Re: Variable Delay Line in C |
Not averaging, linear interpolation. You can get better results wit cubic interpolation, but at a cost. If you change the index points too fast then you will get jumps. On Sun, 24 Apr 2016, Emmett Palaima wrote: > Thank you for your advice and for the example code. > The main thing that I'm still confused on is the type of interpolation that > all these examples use. > > To the best of my understanding what they are doing is taking a sample from > the buffer based on the current delay value, then averaging it with the next > sample in the buffer to smooth out fractional delay values. (e.g. out = > delay[rpi] + frac*(next - delay[rpi]);) > > The confusing thing about this is that it seems it would ONLY smooth out > fractional delay values and wouldn't do anything to help smooth the jumps > through the buffer index that the variable delay creates. If someone could > explain how this works that would clear up a lot for me. > > Thanks! > Csound mailing list Csound@listserv.heanet.ie https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND Send bugs reports to https://github.com/csound/csound/issues Discussions of bugs and features can be posted here |