{"id":451,"date":"2019-11-16T22:12:30","date_gmt":"2019-11-16T22:12:30","guid":{"rendered":"https:\/\/synthnotes.ucsd.edu\/wp4\/?p=451"},"modified":"2019-11-16T22:53:15","modified_gmt":"2019-11-16T22:53:15","slug":"delay-with-feedback","status":"publish","type":"post","link":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/2019\/11\/16\/delay-with-feedback\/","title":{"rendered":"Delay With Feedback"},"content":{"rendered":"\n<p>Adding feedback to a delay is fairly straightforward: <span class=\"wp-katex-eq\" data-display=\"false\"> output = input + delayouput * feedback <\/span>, where <em>feedback<\/em> ranges from 0.0 to 1.0 (and often over 1.0). Adding a feedback path is what creates multiple echoes, with a naturally exponential decay. A typical implementation is to send the delay output to an input\/output mix, and apply feedback gain before the delay output is mixed with the input. In this configuration, <em>mix<\/em> determines the balance of the delay and the input, and <em>feedback<\/em> controls the decay of each echo.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"483\" src=\"https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaynet-1024x483.jpg\" alt=\"\" class=\"wp-image-454\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaynet-1024x483.jpg 1024w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaynet-300x141.jpg 300w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaynet-768x362.jpg 768w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaynet-624x294.jpg 624w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaynet.jpg 1402w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>typical delay configuration with <em>feedback<\/em> and <em>wet.\/dry mix.<\/em><\/figcaption><\/figure>\n\n\n\n<p>Note that <em>delay output * feedback<\/em> + <em>input<\/em>, has a gain of <em>1.0 + feedback<\/em>. This will drive the delay into clipping when there are input signals over 0.5. There are a number of options to control the gain (keep it at 1.0): gain reduction based on feedback, compression, saturation, or a combination of the these. Simple gain reduction would place a gain element before the delay input so that the overall gain is reduced as the feedback increases.<\/p>\n\n\n\n<span class=\"wp-katex-eq\" data-display=\"false\">delayinput = (input + delayoutput * feedback) * (1.0\/(1.0 + feedback))<\/span>\n\n\n\n<p><\/p>\n\n\n\n<p>This is the cleanest sounding approach, but is sometimes felt to be too &#8220;clinical&#8221;. A combination of compressor and saturator is more typically used. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"458\" src=\"https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaycomp-1024x458.jpg\" alt=\"\" class=\"wp-image-456\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaycomp-1024x458.jpg 1024w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaycomp-300x134.jpg 300w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaycomp-768x344.jpg 768w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaycomp-624x279.jpg 624w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delaycomp.jpg 1477w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>compression after feedback\/input mix to keep signal under 1.0<\/figcaption><\/figure>\n\n\n\n<p>This compressor will measure the level before the delay input and apply a gain lower than 1.0 to control the signal. This gain can be applied before the delay input or to the feedback signal.<\/p>\n\n\n\n<p>Finally, when implementing any feedback network, there is a danger of DC offset building up. If using feedback higher than 1.0 this is especially likely. A DC blocking filter (a high pass at a subsonic frequency) in the feedback path should be tuned to remove any DC offset without negatively affecting low frequencies.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Implementation<\/h3>\n\n\n\n<p>The addition of feedback and wet\/dry mix to a delay is fairly simple. Saturation can be added before the delay input. A compressor can be implemented as it was in the earlier section, but in the case where the threshold is fixed and the amount of gain reduction needed is known, a gain table can be kept in memory, or a polynomial can be used to calculate gain. This polynomial can be created by curve fitting through the known gain reduction points (<em>polyfit <\/em> in MatLab can do this, as can several online solvers).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"550\" src=\"https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/Screen-Shot-2019-11-16-at-2.04.49-PM-1024x550.png\" alt=\"\" class=\"wp-image-461\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/Screen-Shot-2019-11-16-at-2.04.49-PM-1024x550.png 1024w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/Screen-Shot-2019-11-16-at-2.04.49-PM-300x161.png 300w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/Screen-Shot-2019-11-16-at-2.04.49-PM-768x413.png 768w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/Screen-Shot-2019-11-16-at-2.04.49-PM-624x335.png 624w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/Screen-Shot-2019-11-16-at-2.04.49-PM.png 1410w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>y=1.60154 &#8211; 1.60573x + 0.88839x^2 &#8211; 0.18048x^3 (gain of 1 at .5, gain of .5 at 2)<\/figcaption><\/figure>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ this code uses the earlier linear interpolation method\nlong writePointer, delayMask;\nfloat *delayBuffer;\nfloat delayTime;\nfloat sampleRate = 48000.0f;\nfloat peak;\n\nvoid DelayInit(long delaySize)\n{\n  delayBuffer = new float[delaySize];\n  delayMask = delaySize - 1;\n  writePointer = 0;\n  delayTime = 0.0f;\n  peak = 0.0f;\n}\n\nvoid DelayTerm(void)\n{\n  delete[] delayBuffer;\n}\n\nvoid Delay(float *input, float *output, long samples, float time, float feedback, float mix)\n{\n  float readPointer; \n  long readPointerLong, i; \n  float fraction; \n  float x0, x1, out, in, rect;\n  delayTimeInc;\n\n  \/\/ find increment to smooth out delayTime\n  delayTimeInc = (time - delayTime)\/samples;\n  for(i = 0; i &lt; samples; i++)\n  {\n    in = *(input+i);\n    \/\/ linear interpolated read\n    readPointer = writePointer + (delayTime*sampleRate); \n    readPointerLong = (long)readPointer; \n    fraction = readPointer - readPointerLong; \n    \/\/ both points need to be masked to keep them within the delay buffer \n    x0 = *(delayBuffer + (readPointerLong &amp; bufferMask)); \n    x1 = *(delayBuffer + ((readPointerLong + 1) &amp; bufferMask)); \n    out = x1 + (x2 - x1) * fraction;\n    \/\/ wet\/dry mix\n    *(output+i) = out * mix + in * (1.0 - mix);\n    \n    \/\/ add feedback output to input\n    rect = in = in + feedback * out;\n\n    \/\/ rectify input for simple peak detection\n    if(rect &lt; 0.0) rect = rect * -1.0;\n    \/\/ if the signal is over the peak, use one pole filter for quick fade of peak to signal\n&nbsp; &nbsp; if(peak &lt; rect)\n &nbsp; &nbsp;  peak = peak + (rect - peak) * 0.9f;\n    \/\/ otherwise fade peak down slowly\n &nbsp; &nbsp;else\n &nbsp; &nbsp;  peak *= 0.9999f;\n    \/\/ polynomial compression\n    \/\/ if feedback goes up to 1.0, a maximum peak of 2.0 is possible\n    if(peak &gt; 2.0)\n      peak = 2.0;\n &nbsp; &nbsp;else if(peak &lt; 0.5f) \n      peak = 0.5f;\n    in = in * (1.601539 - (1.605725 * peak) \n               + (0.8883899 * peak * peak)\n &nbsp;  &nbsp; &nbsp;  &nbsp;     - (0.180484 * peak * peak * peak));\n    \/\/ now it can go in the delay\n    *(delaybuffer + writePointer) = in; \n    \/\/ move the write pointer and wrap it by masking\n    writePointer--; \n    writePointer &amp;= delayMask;\n    \/\/ smooth the delayTime with the increment\n    delayTime = delayTime + delayTimeInc;\n  }\n  delayTime = time;\n}\n\n\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Adding feedback to a delay is fairly straightforward: , where feedback ranges from 0.0 to 1.0 (and often over 1.0). Adding a feedback path is what creates multiple echoes, with a naturally exponential decay. A typical implementation is to send the delay output to an input\/output mix, and apply feedback gain before the delay output [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-451","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/posts\/451","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/comments?post=451"}],"version-history":[{"count":8,"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/posts\/451\/revisions"}],"predecessor-version":[{"id":465,"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/posts\/451\/revisions\/465"}],"wp:attachment":[{"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/media?parent=451"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/categories?post=451"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/tags?post=451"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}