<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[[BLOG] How does DSP work? [Part 2]]]></title><description><![CDATA[<h2>How does DSP work? [Part 2]</h2>
<p dir="auto">Welcome back!</p>
<p dir="auto"><a href="https://forum.hise.audio/topic/14957/blog-how-does-dsp-work-part-1">In the previous part</a>, we saw that audio effects work by changing sample values.<br />
And we saw that a volume effect is just multiplication.</p>
<p dir="auto">Next you might be wondering: how does something like a filter work?<br />
That's the question we are going to answer today.</p>
<p dir="auto">We're going to start with the simplest example of a filter: <strong>a smoother</strong>.</p>
<p dir="auto">A smoother is a low pass filter in its simplest form.<br />
The reason will become clear as we build one.</p>
<h2>Low pass filter</h2>
<p dir="auto">You probably already know that a low-pass filter removes high frequencies.</p>
<p dir="auto">But inside a DSP effect, the audio waveform is just a block of sample values:</p>
<pre><code class="language-text">[0.14,  0.21,  0.08,  0.29,  -0.04,  -0.18,  -0.11,  -0.32,  ...]
</code></pre>
<p dir="auto">Those numbers are the waveform.<br />
So how are we supposed to alter these sample values to remove high frequencies?<br />
let me explain:</p>
<hr />
<p dir="auto">You probably already know that <strong>frequency</strong> is <strong>how fast</strong> a waveform is.</p>
<p dir="auto"><img src="/assets/uploads/files/1785444021080-8900b400-06e0-4b63-942f-936a68c8cbf1-frequency-comparison.png" alt="8900b400-06e0-4b63-942f-936a68c8cbf1-frequency-comparison.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">And of course, a waveform can contain many frequencies at once.<br />
For example, if we add two waves together:</p>
<p dir="auto"><img src="/assets/uploads/files/1785444482934-60fcc656-77ef-4b7b-9e50-79ae592e50f8-frequency-addition.png" alt="60fcc656-77ef-4b7b-9e50-79ae592e50f8-frequency-addition.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">We get a wave that contains high and low frequencies.</p>
<p dir="auto">So how do we remove the high frequencies from this kind of wave?</p>
<p dir="auto">Let's demonstrate with a complex wave.<br />
Here is a waveform with plenty of high-frequency content:</p>
<p dir="auto"><img src="/assets/uploads/files/1785444036794-ac0533dd-f6de-4cfc-855e-f0eda1543b8b-high-frequency-input.png" alt="ac0533dd-f6de-4cfc-855e-f0eda1543b8b-high-frequency-input.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">The broad sine-like shape is low frequency.<br />
The fine, noisy-looking details are higher frequencies.</p>
<p dir="auto">Now watch what happens when we low-pass the sound:</p>
<p dir="auto"><img src="/assets/uploads/files/1785444056446-3133c6e5-070d-44ce-bc48-d498e94b7a77-smoother-audio-stream.gif" alt="3133c6e5-070d-44ce-bc48-d498e94b7a77-smoother-audio-stream.gif" class=" img-fluid img-markdown" /></p>
<p dir="auto">The noisy detail is removed, while the broad low-frequency shape remains.</p>
<p dir="auto">The waveform looks smoothed! A smoothing algorithm can remove the high frequencies!</p>
<h2>A Smoother</h2>
<p dir="auto">So let's look at how a smoother works.</p>
<p dir="auto"><em>[My explanation may be a little hard to follow - bear with me please! I will try and explain it in a few different ways]</em></p>
<p dir="auto">There are many ways to write a smoother.<br />
The version we're going to use generates a new, smoothed waveform in place of the original one.</p>
<p dir="auto">The algorithm works like this:<br />
Every sample, look at the original waveform sample, and move our new waveform sample (the smoothed waveform) towards it.<br />
But only move it a small amount each sample.</p>
<p dir="auto">Here is an animation that shows the algorithm in action:</p>
<p dir="auto"><img src="/assets/uploads/files/1785444097199-34f5e99b-bba3-44c0-9959-e66609a7855c-smoother-homing.gif" alt="34f5e99b-bba3-44c0-9959-e66609a7855c-smoother-homing.gif" class=" img-fluid img-markdown" /></p>
<p dir="auto">Green is the original waveform sample value.<br />
Blue is our smoothed waveform we are creating.</p>
<p dir="auto">We use the green as a "target", and our smoothed value will move towards it over time.</p>
<p dir="auto">Notice how the original (Green) instantly moves to the new sample value, while our smoothed (Blue) value takes a while to catch up.</p>
<p dir="auto">Basically, it's incapable of moving fast!<br />
In other words... it can't be high frequency. Only low frequency!</p>
<p dir="auto">Here is the same process running from sample to sample, on a (very zoomed in) waveform:</p>
<p dir="auto"><img src="/assets/uploads/files/1785444108328-678ed904-48b5-406b-970d-dcfdf6e74f0f-smoother-sample-by-sample.gif" alt="678ed904-48b5-406b-970d-dcfdf6e74f0f-smoother-sample-by-sample.gif" class=" img-fluid img-markdown" /></p>
<p dir="auto">At the right edge, green is the current sample of the original waveform, and blue is our smoothed value.</p>
<p dir="auto">The smoothing algorithm works by starting from the previous blue value, and then moving towards the green target sample value.</p>
<p dir="auto">The resulting smoothed waveform is basically a slow, tired version of the original wave.<br />
It can follow the broad movements, but it can't keep up with quick details</p>
<p dir="auto">The algorithm looks like this:</p>
<pre><code class="language-text">var green;

for each sample in the chunk:
    move the green value partway towards the current sample
    output the green value
</code></pre>
<h2>The Math</h2>
<p dir="auto">Now let's write the smoothing algorithm as pseudocode:</p>
<pre><code class="language-text">amount = 0.1
smoothedValue = 0.0

for each sample in the chunk:
    smoothedValue = lerp(smoothedValue, sample, amount)
    sample = smoothedValue
</code></pre>
<p dir="auto"><code>smoothedValue</code> is the current height of the blue waveform.<br />
It starts at <code>0.0</code>, and it is kept after each sample so that the next calculation can continue from the same height.</p>
<p dir="auto">For each sample, <code>lerp</code> moves <code>smoothedValue</code> towards the height of the original waveform.<br />
The <code>amount</code> controls how far it is allowed to move.</p>
<p dir="auto">An <code>amount</code> of <code>1.0</code> reaches the original sample value immediately.<br />
An <code>amount</code> of <code>0.1</code> only moves one tenth of the distance.</p>
<p dir="auto"><code>lerp</code> is short for a <strong>linear interpolation</strong> function.<br />
In this case, it calculates a new sample value (height) between the current <code>smoothedValue</code> and the original <code>sample</code>.</p>
<p dir="auto">The calculation inside <code>lerp</code> is:</p>
<pre><code class="language-text">smoothedValue += (sample - smoothedValue) * amount
</code></pre>
<p dir="auto"><code>sample - smoothedValue</code> measures the distance between the blue value and the green target.<br />
Multiplying that distance by <code>amount</code> chooses how much of the distance to travel.<br />
Adding the result to <code>smoothedValue</code> moves the blue value towards the green one.</p>
<p dir="auto">Finally, we output the <code>smoothedValue</code>.</p>
<p dir="auto">Because every calculation continues from the value calculated for the previous sample, repeating this process across the waveform for every sample in the buffer, produces <strong>exponential smoothing</strong>.</p>
<h2>In HISE-Style C++</h2>
<p dir="auto">The same calculation in C++ looks like this:</p>
<p dir="auto"><img src="/assets/uploads/files/1785444136733-d73cd8ed-bac2-49f3-b048-37d8fd090538-hise-smoother-cpp.png" alt="d73cd8ed-bac2-49f3-b048-37d8fd090538-hise-smoother-cpp.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">Some trivia:<br />
That stored value is called the filter's <strong>state</strong>.<br />
Because each result depends on the result from the sample before it, this is a <strong>recursive filter</strong>, also called an <strong>IIR filter</strong>.<br />
With one stored value per channel, this particular algorithm is called a <strong>one-pole low-pass filter</strong>.</p>
<h2>Cutoff Frequency</h2>
<p dir="auto">Our example code uses a fixed <code>amount</code> of <code>0.1</code>.</p>
<p dir="auto">If we set <code>amount</code> to <code>1.0</code>, the smoothed value reaches every sample immediately.<br />
Nothing is smoothed.</p>
<p dir="auto">With a smaller amount, the smoothed value takes longer to reach each sample:<br />
The smoothed value changes more slowly, so more high-frequency detail is flattened.</p>
<p dir="auto">When this calculation is used in an audio filter effect, the control is normally presented as a cutoff frequency in Hz.<br />
This is done using some extra conversion math.<br />
The cutoff frequency and Daw sample rate are then converted into the <code>amount</code> used by the code.</p>
<p dir="auto"><img src="/assets/uploads/files/1785444154678-0a10c413-0615-417a-addf-7e62f0c8db05-smoother-filter-curve.gif" alt="0a10c413-0615-417a-addf-7e62f0c8db05-smoother-filter-curve.gif" class=" img-fluid img-markdown" /></p>
<p dir="auto">^ The smoother with changing <code>amount</code> (cutoff):</p>
<p dir="auto">At a low cutoff, the blue waveform loses most of its fine detail.<br />
As the cutoff rises, the blue waveform follows more of the detail.</p>
<h2>Other Audio Filters</h2>
<p dir="auto">The smoother I showed you is a real one-pole low-pass filter.<br />
Its slope is a gentle 6 dB per octave!</p>
<p dir="auto">But audio filters can also have steeper slopes, resonance, and completely different shapes:</p>
<p dir="auto"><img src="/assets/uploads/files/1785444180020-3ea5832f-160a-4b28-8900-2aff4a699c90-hise-filter-node.png" alt="3ea5832f-160a-4b28-8900-2aff4a699c90-hise-filter-node.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">Different filter calculations produce different frequency responses:</p>
<p dir="auto"><img src="/assets/uploads/files/1785444164980-1d75aa82-d3b5-45c0-ae69-8e10ef6e9b2a-filter-response-family.png" alt="1d75aa82-d3b5-45c0-ae69-8e10ef6e9b2a-filter-response-family.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">More advanced filters store more values, and combine them in different ways.</p>
<p dir="auto">Two useful names to look for are <strong>state-variable filters</strong> and <strong>biquad filters</strong>.<br />
You can find the algorithms for these online, and they are also implemented in HISE's <code>Filter</code> node.</p>
<p dir="auto">HISE provides a <a href="https://docs.hise.dev/scriptnode/list/filters/svf.html" rel="nofollow ugc">state-variable filter node</a>.<br />
<a href="https://www.musicdsp.org/en/latest/Filters/142-state-variable-filter-chamberlin-version.html" rel="nofollow ugc">MusicDSP's Chamberlin state-variable filter</a> provides a compact explanation and working algorithms for SVF filters.<br />
The <a href="https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html" rel="nofollow ugc">Audio EQ Cookbook</a> contains the standard equations for many familiar EQ filter shapes.</p>
<h2>To Recap</h2>
<p dir="auto">Inside a DSP effect, the audio waveform is made up of chunks of sample values.</p>
<p dir="auto">For a one-pole smoother, each sample we calculate a new value partway between its previous result and the incoming sample.</p>
<p dir="auto">This adds resistance to fast changes, and suppresses the fine detail in the waveform.</p>
<p dir="auto">That "fast detail" contains high-frequency content, so the high frequencies become quieter when we do this.</p>
]]></description><link>https://forum.hise.audio/topic/14965/blog-how-does-dsp-work-part-2</link><generator>RSS for Node</generator><lastBuildDate>Fri, 31 Jul 2026 03:31:52 GMT</lastBuildDate><atom:link href="https://forum.hise.audio/topic/14965.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 30 Jul 2026 20:43:27 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to [BLOG] How does DSP work? [Part 2] on Thu, 30 Jul 2026 21:02:40 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="https://forum.hise.audio/uid/3542">@griffinboy</a> Thanks for this. Put a link to part 1 at the top.</p>
]]></description><link>https://forum.hise.audio/post/122267</link><guid isPermaLink="true">https://forum.hise.audio/post/122267</guid><dc:creator><![CDATA[David Healey]]></dc:creator><pubDate>Thu, 30 Jul 2026 21:02:40 GMT</pubDate></item></channel></rss>