Czytanie plików * .wav w Pythonie

90

Muszę przeanalizować dźwięk zapisany w pliku .wav. W tym celu muszę przekształcić ten plik w zestaw liczb (na przykład tablice). Myślę, że muszę skorzystać z pakietu Wave. Nie wiem jednak, jak to dokładnie działa. Na przykład wykonałem następujące czynności:

import wave
w = wave.open('/usr/share/sounds/ekiga/voicemail.wav', 'r')
for i in range(w.getnframes()):
    frame = w.readframes(i)
    print frame

W wyniku tego kodu spodziewałem się zobaczyć ciśnienie akustyczne jako funkcję czasu. Dla kontrastu widzę wiele dziwnych, tajemniczych symboli (które nie są liczbami szesnastkowymi). Czy ktoś może mi w tym pomóc, proszę?

rzymski
źródło

Odpowiedzi:

109

Per dokumentacji , scipy.io.wavfile.read(somefile)zwraca krotki z dwóch elementów: pierwszy to częstotliwość próbkowania w próbkach na sekundę, druga to numpytablica zawierająca wszystkie dane odczytane z pliku:

from scipy.io import wavfile
samplerate, data = wavfile.read('./output/audio.wav')
Alex Martelli
źródło
Możesz połączyć to z narzędziami do konwersji wiersza poleceń, aby otworzyć inne formaty.
endolit
11
Poważnie brakuje mu jednak liczby kanałów. Jak masz pracować z dźwiękiem, nie znając liczby kanałów?
bastibe
wyrzuca dziwne błędy podczas rozpakowywania struktury na moim komputerze. Myślę, że używa struct.unpack ('<i', data) zamiast struct.unpack ('<h', data) nak używanego poniżej.
Alex S,
1
Czy ta biblioteka działa? Mam kilka problemów: scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / examples / data / house_lo.wav') -> Brak danych. scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / examples / data / secosmic_lo.wav') -> ZeroDivisionError: dzielenie liczby całkowitej lub modulo przez zero
Finn Årup Nielsen
6
@bastibe datato dwuwymiarowa tablica numpy, więc data.shapezwraca krotkę (num_samples, num_channels)
hobs
63

Korzystając z structmodułu , możesz wziąć ramki wave (które są w binarnych komplementarnych 2 między -32768 a 32767 (tj. 0x8000I 0x7FFF). Czyta to plik MONO, 16-BIT, WAVE. Ta strona internetowa jest bardzo przydatna przy formułowaniu tego:

import wave, struct

wavefile = wave.open('sine.wav', 'r')

length = wavefile.getnframes()
for i in range(0, length):
    wavedata = wavefile.readframes(1)
    data = struct.unpack("<h", wavedata)
    print(int(data[0]))

Ten fragment odczytuje 1 ramkę. Aby odczytać więcej niż jedną ramkę (np. 13), użyj

wavedata = wavefile.readframes(13)
data = struct.unpack("<13h", wavedata)
nak
źródło
2
jak radzić sobie z plikami stereo 24-bitowymi?
Basj
14
to daje mi błąd: „struct.error: unpack wymaga argumentu w postaci ciągu o długości 2”
Coder404
1
Jeśli uruchomisz ten fragment kodu z bardzo dużym plikiem audio. Twój komputer umrze z powodu zapotrzebowania na pamięć przez ten program. Konieczność przetwarzania pliku audio po bloku dla dużego pliku audio
ArthurLambert
@ Coder404 Prawdopodobnie masz plik stereo wave lub inną głębię bitową.
jmilloy
3
Dla tych, którzy, tak jak ja, zastanawiają się, co to jest binarny komplementarny 2s, zobacz tutaj stackoverflow.com/questions/1049722/what-is-2s-complement
Dennis Golomazov
34

Różne moduły Pythona do odczytu plików wav:

Istnieją co najmniej następujące biblioteki do odczytu plików audio Wave:

Najprostszy przykład:

Oto prosty przykład z SoundFile:

import soundfile as sf
data, samplerate = sf.read('existing_file.wav') 

Format wyjścia:

Uwaga, dane nie zawsze mają ten sam format, który zależy od biblioteki. Na przykład:

from scikits import audiolab
from scipy.io import wavfile
from sys import argv
for filepath in argv[1:]:
    x, fs, nb_bits = audiolab.wavread(filepath)
    print('Reading with scikits.audiolab.wavread:', x)
    fs, x = wavfile.read(filepath)
    print('Reading with scipy.io.wavfile.read:', x)

Wynik:

Reading with scikits.audiolab.wavread: [ 0.          0.          0.         ..., -0.00097656 -0.00079346 -0.00097656]
Reading with scipy.io.wavfile.read: [  0   0   0 ..., -32 -26 -32]

Zwrot SoundFile i Audiolab płynie między -1 a 1 (tak jak robi to matab, jest to konwencja dla sygnałów audio). Scipy i Wave zwracają liczby całkowite, które można przekonwertować na liczby zmiennoprzecinkowe w zależności od liczby bitów kodowania, na przykład:

from scipy.io.wavfile import read as wavread
samplerate, x = wavread(audiofilename)  # x is a numpy array of integers, representing the samples 
# scale to -1.0 -- 1.0
if x.dtype == 'int16':
    nb_bits = 16  # -> 16-bit wav files
elif x.dtype == 'int32':
    nb_bits = 32  # -> 32-bit wav files
max_nb_bit = float(2 ** (nb_bits - 1))
samples = x / (max_nb_bit + 1)  # samples is a numpy array of floats representing the samples 
PatriceG
źródło
14

IMHO, najłatwiejszym sposobem na pobranie danych audio z pliku dźwiękowego do tablicy NumPy jest SoundFile :

import soundfile as sf
data, fs = sf.read('/usr/share/sounds/ekiga/voicemail.wav')

Obsługuje również pliki 24-bitowe po wyjęciu z pudełka.

Dostępnych jest wiele bibliotek plików dźwiękowych, napisałem przegląd, w którym można zobaczyć kilka zalet i wad. Zawiera również stronę wyjaśniającą, jak odczytać 24-bitowy plik WAV za pomocą wavemodułu .

Matthias
źródło
Uwaga: soundfile.read () normalizuje się o 2 ^ (n_bits - 1), jak w przykładzie pliku scipy.io.wav firmy Sandoval
Quetzalcoatl
9

Możesz to osiągnąć za pomocą modułu scikits.audiolab . Do działania wymaga NumPy i SciPy, a także libsndfile.

Uwaga, udało mi się uruchomić go tylko na Ubunutu, a nie na OSX.

from scikits.audiolab import wavread

filename = "testfile.wav"

data, sample_frequency,encoding = wavread(filename)

Teraz masz dane wav

ch3rryc0ke
źródło
scikits.audiolabnie był aktualizowany od 2010 roku i prawdopodobnie jest to tylko Python 2.
Boris
4

Jeśli chcesz przetwarzać dźwięk blok po bloku, niektóre z podanych rozwiązań są dość okropne w tym sensie, że implikują ładowanie całego dźwięku do pamięci, powodując wiele błędów w pamięci podręcznej i spowalniając program. python-wavefile zapewnia pewne konstrukcje Pythona do przetwarzania NumPy blok po bloku przy użyciu wydajnego i przejrzystego zarządzania blokami za pomocą generatorów. Inne niuanse Pythona to menedżer kontekstu dla plików, metadane jako właściwości ... i jeśli chcesz mieć cały interfejs pliku, ponieważ tworzysz szybki prototyp i nie zależy Ci na wydajności, cały interfejs pliku jest nadal dostępny.

Prostym przykładem przetwarzania byłoby:

import sys
from wavefile import WaveReader, WaveWriter

with WaveReader(sys.argv[1]) as r :
    with WaveWriter(
            'output.wav',
            channels=r.channels,
            samplerate=r.samplerate,
            ) as w :

        # Just to set the metadata
        w.metadata.title = r.metadata.title + " II"
        w.metadata.artist = r.metadata.artist

        # This is the prodessing loop
        for data in r.read_iter(size=512) :
            data[1] *= .8     # lower volume on the second channel
            w.write(data)

Przykład ponownie wykorzystuje ten sam blok do odczytu całego pliku, nawet w przypadku ostatniego bloku, który jest zwykle mniejszy niż wymagany rozmiar. W tym przypadku otrzymasz kawałek bloku. Dlatego zaufaj zwróconej długości bloku zamiast używać zakodowanego na stałe rozmiaru 512 do dalszego przetwarzania.

vokimon
źródło
1

Jeśli masz zamiar wykonywania przelewów na danych falowych to może należy użyć scipy konkretnie scipy.io.wavfile.

Ignacio Vazquez-Abrams
źródło
2
OK. Właśnie zainstalowałem SciPy, ale nie mogę znaleźć żadnego przykładu użycia scipy.io.wavfile.
Roman
6
Nie ma to jak interaktywny tłumacz, który pomaga dowiedzieć się, jak to działa! Bądź ambitny!
Ignacio Vazquez-Abrams
1

Musiałem odczytać 1-kanałowy 24-bitowy plik WAV. Powyższy post Naka był bardzo przydatny. Jednak, jak wspomniano powyżej, 24-bitowy basj nie jest prosty. W końcu udało mi się go uruchomić, używając następującego fragmentu kodu:

from scipy.io import wavfile
TheFile = 'example24bit1channelFile.wav'
[fs, x] = wavfile.read(TheFile)

# convert the loaded data into a 24bit signal

nx = len(x)
ny = nx/3*4    # four 3-byte samples are contained in three int32 words

y = np.zeros((ny,), dtype=np.int32)    # initialise array

# build the data left aligned in order to keep the sign bit operational.
# result will be factor 256 too high

y[0:ny:4] = ((x[0:nx:3] & 0x000000FF) << 8) | \
  ((x[0:nx:3] & 0x0000FF00) << 8) | ((x[0:nx:3] & 0x00FF0000) << 8)
y[1:ny:4] = ((x[0:nx:3] & 0xFF000000) >> 16) | \
  ((x[1:nx:3] & 0x000000FF) << 16) | ((x[1:nx:3] & 0x0000FF00) << 16)
y[2:ny:4] = ((x[1:nx:3] & 0x00FF0000) >> 8) | \
  ((x[1:nx:3] & 0xFF000000) >> 8) | ((x[2:nx:3] & 0x000000FF) << 24)
y[3:ny:4] = (x[2:nx:3] & 0x0000FF00) | \
  (x[2:nx:3] & 0x00FF0000) | (x[2:nx:3] & 0xFF000000)

y = y/256   # correct for building 24 bit data left aligned in 32bit words

Jeśli potrzebujesz wyników między -1 a +1, wymagane jest dodatkowe skalowanie. Może niektórym z was może się to przydać

ProgJos
źródło
0

jeśli to tylko dwa pliki, a częstotliwość próbkowania jest znacznie wysoka, możesz je po prostu przeplatać.

from scipy.io import wavfile
rate1,dat1 = wavfile.read(File1)
rate2,dat2 = wavfile.read(File2)

if len(dat2) > len(dat1):#swap shortest
    temp = dat2
    dat2 = dat1
    dat1 = temp

output = dat1
for i in range(len(dat2)/2): output[i*2]=dat2[i*2]

wavfile.write(OUTPUT,rate,dat)
leec
źródło
0

Możesz również skorzystać z prostej import waviobiblioteki, ale musisz mieć podstawową wiedzę na temat dźwięku.

yunus
źródło
0

PyDub ( http://pydub.com/ ) nie został wspomniany i należy to naprawić. IMO to obecnie najbardziej wszechstronna biblioteka do odczytywania plików audio w Pythonie, choć nie jest pozbawiona wad. Czytanie pliku wav:

from pydub import AudioSegment

audio_file = AudioSegment.from_wav('path_to.wav')
# or
audio_file = AudioSegment.from_file('path_to.wav')

# do whatever you want with the audio, change bitrate, export, convert, read info, etc.
# Check out the API docs http://pydub.com/

PS. Przykład dotyczy czytania pliku wav, ale PyDub może obsługiwać wiele różnych formatów po wyjęciu z pudełka. Zastrzeżenie polega na tym, że jest on oparty zarówno na natywnej obsłudze formatu wav Pythona, jak i na ffmpeg, więc musisz mieć zainstalowany ffmpeg, a wiele funkcji pydub zależy od wersji ffmpeg. Zwykle jeśli ffmpeg może to zrobić, tak samo może być pydub (który jest dość potężny).

Brak zastrzeżenia: nie jestem związany z projektem, ale jestem ciężkim użytkownikiem.

wanaryytel
źródło