Bruke Python til ? manipulere og spille av lyd

L?ringsm?l denne uken

Denne uken skal vi jobbe med lyd i Python. Vi skal se at lyd egentlig bare er b?lger, og at vi enkelt kan representere slike b?lger ved hjelp av en liste (der hvert element representerer b?lgeh?yden p? et gitt tidsrom).

For ? gj?re denne innleveringen trenger du ? ha numpy og simpleaudio installert p? pc-en din.

Installere bibliotekene vi trenger

Denne uken trenger vi noen biblioteker som ikke er standard i Python:

Linkene over inneholder instrukser for ? installere disse bibliotekene, og det b?r g? greit ? installere disse b?de p? Windows, Mac og Linux gitt at du har pip installert f?rst.

Hvis du har Python3 installert slik at du vanligvis kj?rer python3 program.py i terminalen n?r du kj?rer Python-programmer, har du sannsynligvis ogs? pip tilgjengelig, og kan installere en pakke slik:

# Installer simpleaudio ved ? skrive dette i terminalen:
python3 -m pip install simpleaudio
# Tilsvarende for numpy:
python3 -m pip install numpy
# Tilsvarende for matplotlib:
python3 -m pip install matplotlib

NB: Noen ganger (kanskje bare p? linux?) kan det v?re n?dvendig med sudo f?rst, alts? sudo python3 -m pip install ...

NB 2: Hvis du kj?rer Python3 med kommandoen python, s? m? du bytte ut python3 med python i instruksene over.

NB 3: Hvis du er vant med ? installere pakker via Conda, skal det g? fint som alternativ til pip.

Hvis installasjonene fungerer skal du kunne lage en python-fil med disse tre linjene og kj?re den uten ? f? noen feilmeldinger:

import numpy
import simpleaudio
import matplotlib

Hvis du st?r fast, send gjerne en e-post til ivargry@ifi.uio.no. Beskriv hva du har pr?vd og hvor du st?r fast.

Kort introduksjon

Bruke simpleaudio i Python

Hvis du har f?tt til ? installere simpleaudio og NumPy ved ? f?lge instruksene over, er du klar for denne ukens opplegg.

For ? gj?re ting enklere for oss, ?nsker vi ? ha en funksjon som kan ta en liste som parameter og spille av lyden som den listen representerer. Dette krever noen kall til numpy (for ? omgj?re listen til bytes som maskinen kan spilles av) og til simpleaudio. Lag en fil lyd.py hvor du starter med denne koden:

import simpleaudio
import numpy as np

def spill_lyd(lydliste):
    lyd = np.array(lydliste).astype(np.int16)
    lydobjekt = simpleaudio.play_buffer(lyd, 1, 2, 44100)
    lydobjekt.wait_done()

I kallet til simpleaudio.play_buffer spesifiserer vi at lyden v?r har "sample-rate" 44100, som betyr at vi har 44100 verdier (samples) i sekundet. Simpleaudio vil da prosessere og spille av listen vi sender inn i en slik hastighet at det blir spilt av 44100 verdier i sekundet.

Teste ut simpleaudio med st?y

Vi lager en funksjon tilfeldig_lyd(antall_sekunder) som lager en lyd som skal vare i antall_sekunder der hver lyd-verdi er et tilfeldig tall mellom 0 og 32000. Funksjonen skal lage returnere en liste som representerer lyden.

PS: En lyd som skal vare i et sekund m? ha 44100 verdier, en lyd som skal vare i 2 sekunder m? ha det dobbelte av det, osv.

# Legg denne linjen ?verst i filen
from random import randint

def tilfeldig_lyd(antall_sekunder):
    lyd = []
    for i in range(44100 * antall_sekunder):
        lyd.append(randint(0, 32767))

    return lyd

spill_lyd(tilfeldig_lyd(4))

OBS! Det kan v?re lurt ? skru ned volumet en del f?r man spiller av disse lydene.

Oppgave: Lag en funksjon som returnerer en lyd (liste) der de f?rste 50 verdiene er 0, de neste 50 verdiene er 32000, de neste 50 er 0, osv ... Hvordan h?res lyden ut?

Spille rene toner

Lyden vi lagde i forrige oppgave ser omtrent slik ut hvis vi hadde plottet den som en graf:

plott

Lyden er faktisk en ren A (i musikkverden). Hvis du spiller en A p? en gitar, vil strengen vibrere 440 ganger i sekundet (440 b?lgetopper/daler i sekundet). Det har lyden du lagde ogs?.

Lyden du lagde h?res derimot litt hakkete ut. Det er fordi det ikke er helt naturlige b?lger (som du ser p? plottet).

Oppgave: Lag en funksjon lyd_trekant(antall_sekunder) som returnerer en lyd som ser slik ut:

plott

H?res denne lyden bedre ut enn den "firkantede"?

Enda bedre lyd (perfekt sinus-kurve)

Den "trekantede" lyden var mer behagelig ? h?re p? enn den firkantede. Lyd i naturen er stort sett mer lik naturlige b?lger (som b?lger p? et hav), og har mye mykere svingninger:

plott

En slik lyd kan genereres slik:

def lyd_sinus(antall_sekunder):
    lyd = []
    for i in range(44100 * antall_sekunder):
        lyd.append(16000 * (1 + np.sin(440 * i/44100 * 2 * np.pi)))
    return lyd

Spille toner med en gitt frekvens

I koden over ganger vi en del tall med 440, og f?r dermed en lyd som svinger 440 ganger i sekundet (akkurat hvordan matematikken fungerer her trenger du ikke tenke p?, annet enn at det magiske tallet 440 f?rer til det blir 440 b?lgetopper/-bunner i sekundet).

Oppgave: Endre koden slik at funksjonen tar enda et parameter som er antall svingninger i sekundet og bruk det parameteret i stedet for 440. Denne funksjonen som tar to parametere vil du trenge i obligen denne uken.