{"id":430,"date":"2019-11-13T01:04:15","date_gmt":"2019-11-13T01:04:15","guid":{"rendered":"https:\/\/synthnotes.ucsd.edu\/wp4\/?p=430"},"modified":"2019-11-13T01:04:15","modified_gmt":"2019-11-13T01:04:15","slug":"introduction-single-echo-delay","status":"publish","type":"post","link":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/2019\/11\/13\/introduction-single-echo-delay\/","title":{"rendered":"Introduction: Single Echo Delay"},"content":{"rendered":"\n<h3 class=\"wp-block-heading\">Introduction<\/h3>\n\n\n\n<p>Delay effect design draws on a number of previously explored techniques. Wavetable interpolation will be used to read samples from the delay. Compression and saturation will be used to maintain the gain within the feedback loop. Filtering will be used to remove high or low frequencies from the echoes. A delay starts with a fairly straightforward design, but becomes complex with the integration of these techniques, and gathers its individual character as design decisions are made.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Design<\/h3>\n\n\n\n<p>To create a delay, we need a sample buffer to hold audio until the delayed signal is played. Input samples will continually be written to this buffer, and output samples will continually be read from this buffer. To do this, point the input sample to a starting location, write the sample, and move the input pointer one sample over. The output pointer is positioned relative to the input pointer, with the delay time in samples separating them. If the delay time is 1.4 seconds, and the sample rate is 48k, the separation between input and output pointer is 1.4 x 48000 or 67200 samples.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"344\" src=\"https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay1-1024x344.jpg\" alt=\"\" class=\"wp-image-432\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay1-1024x344.jpg 1024w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay1-300x101.jpg 300w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay1-768x258.jpg 768w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay1-624x210.jpg 624w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay1.jpg 1224w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>If unlimited storage is available, the input pointer and output pointer could move indefinitely. A large storage space could be used: a 1TB flash drive could run a delay at 48k\/32 bit for 30 days before running out of memory. However, much smaller and faster memory is more typically used for the sample buffer. Because of this, it is typical to reuse the memory &#8211; after the input pointer reaches the last sample, it resets to the first sample. This is called a circular buffer. A large enough buffer is needed for the longest delay time desired. For a 42 second delay, with a sample rate of 48k, enough memory to hold\u00a042 * 48,000 \u00a0or 2,016,000 samples is needed. For sample addressing convenience (discussed later), we will use the nearest power of 2. In this case it is 2^21 or\u00a02,097,152 samples.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"548\" src=\"https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay2-1024x548.jpg\" alt=\"\" class=\"wp-image-433\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay2-1024x548.jpg 1024w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay2-300x161.jpg 300w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay2-768x411.jpg 768w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay2-624x334.jpg 624w, https:\/\/synthnotes.ucsd.edu\/wp4\/wp-content\/uploads\/2019\/11\/delay2.jpg 1224w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Implementation<\/h3>\n\n\n\n<p>On embedded processors, it is typical to use physical memory for the circular buffer. In that case we could just use an array declaration. For a plugin or app, memory allocation is necessary. The functions <em>malloc<\/em> (C) or <em>new<\/em> (C++) would be used to create the sample buffer.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ C example of delay memory allocation\nfloat *delayBuffer;\nlong delaySize, delayMask;\ndelaySize = 2097152;\ndelayMask = delaySize - 1;\ndelayBuffer = (float *)malloc(delaySize * sizeof(float));<\/pre>\n\n\n\n<p>Pointer arithmetic is used to determine the memory location to write the input sample. After the sample is written, <em>writePointer<\/em> is moved one sample. In the diagrams above <em>writePointer<\/em> is incremented. However, it makes our program simpler if <em>writePointer<\/em> is decremented. This is because <em>readPointer<\/em> is calculated by adding the delay in samples to <em>writePointer<\/em>. After decrementing, a bitwise AND is used to maintain the circular buffer (to make sure <em>writePointer<\/em> is between 0 and delaySize).<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ C example of putting sample in delayBuffer, \n\/\/ decrementing and wrapping writePointer\n*(delayBuffer + writePointer) = inputSample;\nwritePointer--;\nwritePointer &amp;= delayMask;<\/pre>\n\n\n\n<p>To complete our echo, the delayed sample should be read out using <em>readPointer<\/em>. Its position is relative to <em>writePointer<\/em>: <span class=\"wp-katex-eq\" data-display=\"false\"> readPointer = writePointer + (delayTime * sampleRate) <\/span>. As with <em>writePointer<\/em>, a bitwise AND will keep <em>readPointer<\/em> between 0 and delaySive.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">readPointer = writePointer + (long)(delayTime*sampleRate);\nreadPointer &amp;= delayMask;\noutputSample = *(delaybuffer+readPointer);\n\n*(delaybuffer + writePointer) = inputSample;\nwritePointer--;\nwritePointer &amp;= delayMask;<\/pre>\n\n\n\n<p>Note that the delay buffer is read before it is written. The reason for this will become apparent when feedback is added to create multiple echoes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Delay effect design draws on a number of previously explored techniques. Wavetable interpolation will be used to read samples from the delay. Compression and saturation will be used to maintain the gain within the feedback loop. Filtering will be used to remove high or low frequencies from the echoes. A delay starts with a [&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-430","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\/430","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=430"}],"version-history":[{"count":3,"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/posts\/430\/revisions"}],"predecessor-version":[{"id":435,"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/posts\/430\/revisions\/435"}],"wp:attachment":[{"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/media?parent=430"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/categories?post=430"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/synthnotes.ucsd.edu\/wp4\/index.php\/wp-json\/wp\/v2\/tags?post=430"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}