2020-04-26-distortion.markdown 10.3 KB
Newer Older
Ben Sheron's avatar
Ben Sheron committed
1
2
3
---
layout: post
title:  "How Distortion Works in Music"
4
5
date:   2020-04-26 16:25:00 +0100
tags: [distortion, waveshaping, javascript, waveshaper]
Ben Sheron's avatar
Ben Sheron committed
6
7
---

8
9
![Distorted Signal](/blog/assets/distorted-signal.jpg)

Ben Sheron's avatar
Ben Sheron committed
10
11
Distortion is everywhere in music, especially when electric guitars are involved. It's the crunchy, fuzzy sound that makes rock music sound rocky. It came into existence by accident when too much signal was fed into analogue components and people realised it made an interesting sound.

Ben Sheron's avatar
Ben Sheron committed
12
One of the reasons it sounds so cool is that it preserves the frequency of the note being played, while adding other frequencies on top. With analogue components, this (sort of) works by clipping the signal used to generate the sound. The end result depends on the circuits and components used, so there's a lot of variety. The right distortion can add character to any sound.
Ben Sheron's avatar
Ben Sheron committed
13
14
15
16
17

In the digital world, distortion is commonly created using a technique called wave shaping, which is a cool concept that I thought deserved a blog post. You can use wave shaping to create a simple clipping distortion, but it can do a few more things as well.

# Housekeeping

18
Everything below this paragraph needs javascript enabled to run, the source code is [here](https://gitlab.com/benmosheron/blog/-/blob/master/_posts/2020-04-26-distortion.markdown) if you don't trust me. I'm using some sound demos based on pure sine waves which sound utterly horrible, but the graphs are so much prettier. I've made sure things aren't too loud but make sure your volume isn't turned up super high. The sounds get better at the end.
Ben Sheron's avatar
Ben Sheron committed
19
20
21
22
23

I know some of you will be viewing this on a phone. Good luck, _technically_ it should work.

# Master volume control

24
Use this to change the volume of every sound on this page. Click each graph to play its sound, and click again to stop.
Ben Sheron's avatar
Ben Sheron committed
25
26
27
28
29
30
31

<div class="slider-container" height="100px" width="500px">
  <input id="masterVolumeSlider" class="slider" type="range" min="0" max="100" value="50" >
</div>

# Pure Sine Wave

32
This is a basic sine wave playing at 440Hz (an A note) with clipping, you can fade between the clipped and not-clipped waves and adjust the clipping level using the sliders below.
Ben Sheron's avatar
Ben Sheron committed
33
34

<div class="pad-lower">
Ben Sheron's avatar
Ben Sheron committed
35
  <canvas id="clippedSineCanvas0" class="engine clear clipped-sine" height="300px" width="600px"></canvas>
Ben Sheron's avatar
Ben Sheron committed
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
</div>

Cross fade between pure sine wave and clipped:

<div class="slider-container" height="100px" width="500px">
  <input id="crossfadePureClippedSlider" class="slider" type="range" min="0" max="100" value="50" >
</div>

Change the amount of clipping:

<div class="slider-container" height="100px" width="500px">
  <input id="clippingAmountSlider0" class="slider" type="range" min="0" max="100" value="50" >
</div>

When the clipping value is outside the usual value of the wave, the clipped sine wave sounds exactly the same as the pure sine wave. I told you they sound horrible...

# Nicer Sounds

Groups of sine waves sound slightly less bad than single waves, mathematicians out there will know you can form any sound with a combination of sine waves, but I'm not going that far.

56
I'll apply the same clipping to a group of seven sine waves which have frequencies close, but not exactly the same. This makes them interfere with each other in a way which causes a beating effect (it still doesn't sound very nice).
Ben Sheron's avatar
Ben Sheron committed
57

58
A quirk of clipping is that quieter sounds will not hit the threshold, so only the louder sounds get changed. This is how you get "overdrive" effects on loud sounds.
Ben Sheron's avatar
Ben Sheron committed
59
60
61
62
63
64

Another side effect of clipping is that it limits the volume, so the distortion is often paired with a boost to the amplitude.

The waveform here (and above) is being drawn about 100x slower than the sound you can hear:

<div class="pad-lower">
Ben Sheron's avatar
Ben Sheron committed
65
  <canvas id="clippedMultiSineCanvas0" class="engine clear clipped-multi-sine" height="300px" width="600px"></canvas>
Ben Sheron's avatar
Ben Sheron committed
66
67
</div>

Ben Sheron's avatar
Ben Sheron committed
68
This slider changes the distortion amount, further to the right is more clipping coupled with a higher boost:
Ben Sheron's avatar
Ben Sheron committed
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

<div class="slider-container" height="100px" width="500px">
  <input id="clippingAmountSlider1" class="slider" type="range" min="0" max="100" value="50" >
</div>

# Wave Shaping

Under the hood I'm using a technique called wave shaping to create the clipped signals. It's often used to emulate more classic distortion sounds which are a bit more involved than clipping. And it can do quite a lot more.

It works by using a transfer function, which maps every <span class="input">input value</span> (between -1 and 1) to an <span class="output">output value</span> also between -1 and 1.

Here are a few examples of transfer functions, the axes on the graph both go from -1 to 1. The cursor position will show example values of the function:

<div class="pad-lower">
  <button id="transfer-function-option-clip" class="transfer-function-option">Clipped</button>
  <button id="transfer-function-option-clbs" class="transfer-function-option">Clip/Boost</button>
  <button id="transfer-function-option-expo" class="transfer-function-option">Exponential</button>
  <button id="transfer-function-option-quad" class="transfer-function-option">Quadratic</button>
  <button id="transfer-function-option-nois" class="transfer-function-option">Noisy</button>
  <button id="transfer-function-option-noi2" class="transfer-function-option">Very Noisy</button>
  <button id="transfer-function-option-line" class="transfer-function-option">Linear</button>
</div>

<div class="pad-lower">
  <button id="transfer-function-option-fold" class="transfer-function-option">Wave Fold</button>
  <button id="transfer-function-option-wrap" class="transfer-function-option">Wave Wrap</button>
</div>

<div class="pad-lower">
  <table id="transform-table" class="no-border">
    <tr class="no-border">
      <td class="no-border">
Ben Sheron's avatar
Ben Sheron committed
101
        <canvas id="transferFunctionCanvas0" class="engine clear transfer-function border no-point" height="400px" width="400px"></canvas>
Ben Sheron's avatar
Ben Sheron committed
102
103
104
105
106
107
108
109
110
111
112
113
      </td>
      <td class="constant-width no-border">
        <p>Input: <span id="transferFunctionInput" class="input" >0</span></p>
        <p>Output: <span id="transferFunctionOutput" class="output" >0</span></p>
      </td>
    </tr>
  </table>
</div>

Below shows the result of applying the transfer function to a sine wave. Click the graph to play the sound, you can change the function by clicking the buttons while it's playing to hear the difference.

<div class="pad-lower">
Ben Sheron's avatar
Ben Sheron committed
114
  <canvas id="tfSineCanvas0" class="engine clear tf-sine border" height="300px" width="600px"></canvas>
Ben Sheron's avatar
Ben Sheron committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
</div>

Some info on the different functions (look at this page's source and search "Hello!" to see the functions themselves):

* **Clipped** - exactly the same as the first example, with clip value of 0.5
* **Clip/Boost** - clips to 0.5 and doubles the amplitude to keep the volume the same
* **Exponential** - rounds the edges a bit, emulates an overdriven analogue system
* **Quadratic** - doubles the frequency
* **Noisy** - adds some random noise on top
* **Very Noisy** - replaces the signal with random noise, but you can still hear the original tone (I think this is due to aliasing)
* **Linear** - leaves the input unchanged, reproducing the original sound
* **Wave Fold** and **Wave Wrap** - emulate analogue circuits which use comparators

## These Sound So Much Better with Real Sounds

Ben Sheron's avatar
Ben Sheron committed
130
Why did I waste so much time on the sine waves? 😢
Ben Sheron's avatar
Ben Sheron committed
131

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
Here are some audio recordings which will be run through the transfer function, I've copied the different distortion buttons below so you can mess about with the sound while it's playing (remember, linear will play the sound unchanged). Have fun!

<div class="pad-lower">
  <button id="transfer-function-option-clip-copy" class="transfer-function-option">Clipped</button>
  <button id="transfer-function-option-clbs-copy" class="transfer-function-option">Clip/Boost</button>
  <button id="transfer-function-option-expo-copy" class="transfer-function-option">Exponential</button>
  <button id="transfer-function-option-quad-copy" class="transfer-function-option">Quadratic</button>
  <button id="transfer-function-option-nois-copy" class="transfer-function-option">Noisy</button>
  <button id="transfer-function-option-noi2-copy" class="transfer-function-option">Very Noisy</button>
  <button id="transfer-function-option-line-copy" class="transfer-function-option">Linear</button>
</div>

<div class="pad-lower">
  <button id="transfer-function-option-fold-copy" class="transfer-function-option">Wave Fold</button>
  <button id="transfer-function-option-wrap-copy" class="transfer-function-option">Wave Wrap</button>
</div>
Ben Sheron's avatar
Ben Sheron committed
148
149
150

# Guitar with Reverb

Ben Sheron's avatar
Ben Sheron committed
151
_These might not work in some browsers, try playing one of the sine waves above first, then email me_
Ben Sheron's avatar
Ben Sheron committed
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241

<audio id="audio0" loop="true" controls>
  <source id="audioSource0" src="/blog/assets/a-few-seconds-of-quarantine-11.mp3" type="audio/mpeg">
</audio>

# Techno with Ring

<audio id="audio1" loop="true" controls>
  <source id="audioSource1" src="/blog/assets/a-few-seconds-of-quarantine-10.mp3" type="audio/mpeg">
</audio>

# Some Final Quirks

The quadratic one sounds so odd. It's because it's an even function whereas most of the others are... odd. These are side effects of the symmetry of the function, they change the harmonics produced by the distortion.

The difference between clip/boost and exponential is subtle - these are the sorts of differences that become very important for high end audio equipment. People will spend lots of time and money looking for the exact right sound.


## The End

I hope you found that cool, I know it's a random subject. I'm building a synthesiser in javascript at the moment, hence the weird topic. Stay tuned or get in touch if you're interested.

<style>

.no-border {
  border: none;
}

button.transfer-function-option {
  width: 100px;
  height: 30px;
}

td.constant-width {
  width: 100px;
}

span.input {
  color: rgb(60,150,200);
}
span.output {
  color: rgb(200,60,150);
}

canvas {
  cursor: pointer;
  padding-left: 0;
  padding-right: 0;
  margin-left: auto;
  margin-right: auto;
  display: block;
}

canvas.border{  
  border: solid;
  border-color: rgb(150,150,150);
}

canvas.no-point {
  cursor: auto;
}

div.pad-lower{
  padding-bottom: 10px;
}

.slider-container {
  padding-left: 0;
  padding-right: 0;
  margin-left: auto;
  margin-right: auto;
  text-align:center;
  display: block;
  width: 500px;
  height: 20px;
  padding: 0;
}

.slider{
  cursor: grab;
  width: 500px;
  height: 20px;
}

</style>

<script>
  {% include engine2.js %}
  {% include distortion.js %}
</script>