Optagelse af søvnlyde
Apps til optagelse af lyde under søvn er blevet meget populære. Jeg var også nysgerrig efter at høre, hvad jeg siger, når jeg sover, og om jeg snorker.
Hvis din telefon kan optage lyd, og din computer kan køre et enkelt Python-script, behøver du hverken købe ekstra udstyr eller betale for et abonnement for at finde nattens højlydte øjeblikke.
Først skal vi optage lyd, mens vi sover. I mit tilfælde startede jeg bare optagelsen på min iPhone, inden jeg gik i seng, og næste morgen havde jeg en otte timer lang M4A-fil.
Det er besværligt at gennemgå så lang en optagelse manuelt, så vi udtrækker kun de fragmenter, der ligger over en valgt lydstyrkegrænse.
Jeg springer opsætningen af Python-miljøet over.
Vi skal kun installere pydub,
et high-level Python-bibliotek til lydbehandling, og oprette et tomt script som sleep.py.
Det simpleste eksempel ser sådan ud:
from pydub import AudioSegment
from pydub.silence import split_on_silence
audio = AudioSegment.from_file("sleep_audio.m4a", format="m4a")
chunks = split_on_silence(audio, silence_thresh=-54)
sum(chunks).export("loud_fragments.mp3", format="mp3")
Her indlæser vi lydfilen og bruger en grænse i dBFS
til at skille de højere fragmenter fra stilheden.
Nul er det maksimale niveau, så -54 betyder 54 decibel under maksimum.
Den sidste linje eksporterer resultatet som en MP3-fil.
Lad os nu gøre behandlingen hurtigere og finjustere et par parametre for at forbedre resultatet:
...
chunks = split_on_silence(
audio,
keep_silence=10_000,
min_silence_len=10_000,
silence_thresh=-54,
seek_step=1_000)
...
keep_silence=10_000: Bevarer ti sekunders stilhed i begyndelsen og slutningen af hvert fragment, så lyden ikke bliver skåret brat af.min_silence_len=10_000: Kræver mindst ti sekunders stilhed, før lyden deles.silence_thresh=-54: Behandler alt under-54dBFS som stilhed.seek_step=1_000: Scanner lyden i trin på ét sekund. Standardværdien er ét millisekund, hvilket gør en otte timer lang optagelse meget langsommere at behandle.
For at skelne ét fragment fra et andet kan vi tilføje et "bip" imellem,
forudgået og efterfulgt af et par sekunders stilhed.
Vi kan også hæve lydstyrken på fragmenterne ved at lægge et antal decibel til, for eksempel chunk + 3.
...
from pydub.generators import Square
...
silence = AudioSegment.silent(duration=500)
beep = Square(1_000).to_audio_segment(duration=250, volume=-54)
beep_with_silence = silence + beep + silence
loud_fragments = sum([(chunk + 3) + beep_with_silence for chunk in chunks])
loud_fragments.export("loud_fragments.mp3", format="mp3")
Den endelige version af mit script ser sådan ud:
import sys
from pathlib import Path
from pydub import AudioSegment
from pydub.generators import Square
from pydub.silence import split_on_silence
GAIN = 3
KEEP_SILENCE = 10_000
MIN_SILENCE_LEN = 60_000
SEEK_STEP = 100
SILENCE_THRESH = -54
def main(file_path):
audio = AudioSegment.from_file(file_path, format="m4a")
print(f"Loaded audio: {audio.duration_seconds} seconds")
chunks = [chunk for chunk in split_on_silence(audio,
keep_silence=KEEP_SILENCE,
min_silence_len=MIN_SILENCE_LEN,
seek_step=SEEK_STEP,
silence_thresh=SILENCE_THRESH)
if chunk.duration_seconds > (KEEP_SILENCE * 2 / 1_000)]
print(f"Found {len(chunks)} chunks")
silence = AudioSegment.silent(duration=500)
beep = Square(1_000).to_audio_segment(duration=250, volume=SILENCE_THRESH)
beep_with_silence = silence + beep + silence
loud_audio = sum([(chunk + GAIN) + beep_with_silence for chunk in chunks])
print(f"Combined loud audio: {loud_audio.duration_seconds} seconds")
Path("./data").mkdir(parents=True, exist_ok=True)
loud_audio.export(f"./data/{Path(file_path).stem}_loud.mp3", format="mp3")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python sleep.py <file_path>")
sys.exit(1)
main(sys.argv[1])
Jeg kører det som python sleep.py myaudio.m4a, og scriptet opretter en kortere version af optagelsen.
Resultatet varer normalt 8 til 12 minutter for otte timers søvn.