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 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 numpy ved ? skrive dette i terminalen:
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 linjene og kj?re den uten ? f? noen feilmeldinger:

import numpy
import matplotlib

Hvis du st?r fast, sp?r p? Discourse. Beskriv hva du har pr?vd og hvor du st?r fast. Det gj?r ikke s? mye om du ikke f?r til ? installere matplotlib.

Kort introduksjon

Teste at du f?r til ? lagre lyd til fil og spille av

Hvis du har f?tt til ? installere 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 lagre denne lyden til en fil som vi s? kan spille av. Dette krever noen kall til NumPy (for ? omgj?re listen til bytes som maskinen kan spilles av). Vi bruker ogs? et innebygd bibiliotek i Python (wave) til ? lagre lyden til fil som vi s? kan spille av. Lag en fil lyd.py hvor du starter med denne koden:

import numpy as np
import wave

def skriv_lyd_til_fil(data, sample_rate, filnavn):
    # tatt fra https://stackoverflow.com/a/64376061
    audio = np.array([data, data]).T
    audio = audio.astype("<h")

    with wave.open(filnavn, "w") as f:
        f.setnchannels(2)
        f.setsampwidth(2)
        f.setframerate(sample_rate)
        f.writeframes(audio.tobytes())
        

Vi ?nsker n? ? lage 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

skriv_lyd_til_fil(tilfeldig_lyd(4), 44100, "min_lyd.wav")

Hvis koden over fungerer vil du f? en fil min_lyd.wav som du s? kan ?pne opp og spille av p? pc-en din (bruk et valgfritt program til ? spille lyden). OBS! Det kan v?re lurt ? skru ned volumet en del f?r man spiller av disse lydene.

I de neste oppgavene vil vi lage flere slike filer. Du kan kalle dem hva du vil, men det kan v?re greit ? bare bruke et fast filnavn slik at du kan ha et enkelt oppsett for ? spille av lyden hver gang du lager en ny lyd.

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 ... Lagre denne lyden til fil og spill av . 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:

# husk ? importere numpy om du ikke har gjort det tidligere i filen:
# import numpy as np

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.