Chapter 10 Preview

The second edition of Think DSP is not for sale yet, but if you would like to support this project, you can buy me a coffee.

Chapter 10 Preview#

Click here to run this notebook on Colab.

Hide code cell content

import importlib, sys
sys.modules["imp"] = importlib

%load_ext autoreload
%autoreload 2

Hide code cell content

# download thinkdsp.py

from os.path import basename, exists

def download(url):
    filename = basename(url)
    if not exists(filename):
        from urllib.request import urlretrieve
        local, _ = urlretrieve(url, filename)
        print('Downloaded ' + local)
        
download("https://github.com/AllenDowney/ThinkDSP/raw/master/thinkdsp/thinkdsp.py")
import numpy as np
import matplotlib.pyplot as plt

from thinkdsp import decorate

LTI System Theory#

This notebook contains one of the coolest examples in Think DSP. It uses LTI system theory to characterize the acoustics of a recording space and simulate the effect this space would have on the sound of a violin performance.

I’ll start with a recording of a gunshot:

Hide code cell content

# download gunshot.wav

from os.path import basename, exists

def download(url):
    filename = basename(url)
    if not exists(filename):
        from urllib.request import urlretrieve
        local, _ = urlretrieve(url, filename)
        print('Downloaded ' + local)
        
download("https://github.com/AllenDowney/ThinkDSP/raw/master/soln/180960__kleeb__gunshot.wav")
from thinkdsp import read_wave

response = read_wave('180960__kleeb__gunshot.wav')

start = 0.12
response = response.segment(start=start)
response.shift(-start)

response.plot()
decorate(xlabel='Time (s)', ylabel='Amplitude')
_images/14d92e836fa992377deedaccee2c90ae2ddbb43dc92f142b50f710beb16bc0e9.png

If you play this recording, you can hear the initial shot and several seconds of echos.

response.make_audio()

This wave records the “impulse response” of the room where the gun was fired.

Now let’s load a recording of a violin performance:

Hide code cell content

# download violin.wav

from os.path import basename, exists

def download(url):
    filename = basename(url)
    if not exists(filename):
        from urllib.request import urlretrieve
        local, _ = urlretrieve(url, filename)
        print('Downloaded ' + local)
        
download("https://github.com/AllenDowney/ThinkDSP/raw/master/soln/92002__jcveliz__violin-origional.wav")
wave = read_wave('92002__jcveliz__violin-origional.wav')
wave.truncate(len(response))
wave.normalize()
wave.plot()
decorate(xlabel='Time (s)', ylabel='Amplitude')
_images/fa27a1c94ce92687043a48be5cbf61aa2bc1334edb6698e6c4ff14394af51d2c.png

And listen to it:

wave.make_audio()

Now we can figure out what the violin would sound like if it was played in the room where the gun was fired. All we have to do is convolve the two waves:

output = wave.convolve(response)
output.normalize()

Here’s what it looks like:

wave.plot(label='original')
output.plot(label='convolved')
decorate(xlabel='Time (s)', ylabel='Amplitude')
_images/0739f195435ff963b7ab83645420787e09fc3e8f6df5d5ae4dd5bc827410fb4a.png

And here’s what it sounds like:

output.make_audio()

If you think this example is black magic, you are not alone. But there is a good reason why this works, and I do my best to explain it in Chapter 10. So stay tuned.

I’d like to thank jcveliz and kleeb for making these recordings available from freesound.org.

Think DSP: Digital Signal Processing in Python, 2nd Edition

Copyright 2024 Allen B. Downey

License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International