Lesen von * .wav-Dateien in Python


88

Ich muss den in einer WAV-Datei geschriebenen Ton analysieren. Dafür muss ich diese Datei in eine Reihe von Zahlen umwandeln (z. B. Arrays). Ich denke, ich muss das Wave-Paket verwenden. Ich weiß jedoch nicht, wie genau es funktioniert. Zum Beispiel habe ich folgendes gemacht:

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

Als Ergebnis dieses Codes erwartete ich, den Schalldruck als Funktion der Zeit zu sehen. Im Gegensatz dazu sehe ich viele seltsame, mysteriöse Symbole (die keine Hexadezimalzahlen sind). Kann mir jemand dabei helfen?

Antworten:


104

Gemäß der Dokumentation wird scipy.io.wavfile.read(somefile)ein Tupel mit zwei Elementen zurückgegeben: Das erste ist die Abtastrate in Stichproben pro Sekunde, das zweite ist ein numpyArray mit allen aus der Datei gelesenen Daten:

from scipy.io import wavfile
samplerate, data = wavfile.read('./output/audio.wav')

Sie können dies mit Befehlszeilenkonvertierungswerkzeugen kombinieren, um andere Formate zu öffnen.
Endolith

11
Es fehlt jedoch ernsthaft die Anzahl der Kanäle. Wie soll man mit Audio arbeiten, ohne die Anzahl der Kanäle zu kennen?
Bastibe

wirft einige seltsame Strukturentpackungsfehler auf meinen Computer. Ich denke, es wird struct.unpack ('<i', Daten) anstelle des unten verwendeten struct.unpack ('<h', Daten) nak verwendet.
Alex S

1
Funktioniert diese Bibliothek? Ich habe eine Reihe von Problemen: scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / examples / data / house_lo.wav') -> Keine Daten. scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / examples / data / secosmic_lo.wav') -> ZeroDivisionError: Ganzzahldivision oder Modulo durch Null
Finn Årup Nielsen

6
@ Bastibe dataist ein 2-D-Numpy-Array, data.shapegibt also ein Tupel von (num_samples, num_channels) zurück
Kochfelder

63

Mit dem structModul können Sie die Wave-Frames (die sich in der komplementären Binärdatei von 2 zwischen -32768 und 32767 befinden (dh 0x8000und 0x7FFF)) lesen. Dies liest eine MONO, 16-BIT, WAVE-Datei. Ich fand diese Webseite sehr nützlich, um dies zu formulieren:

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]))

Dieses Snippet liest 1 Frame. Verwenden Sie zum Lesen von mehr als einem Frame (z. B. 13)

wavedata = wavefile.readframes(13)
data = struct.unpack("<13h", wavedata)

2
Wie gehe ich mit 24-Bit-Stereodateien um?
Basj

12
Dies gibt mir den Fehler: "struct.error: Unpack erfordert ein String-Argument der Länge 2"
Coder404

1
Wenn Sie diesen Code mit einer sehr großen Audiodatei ausführen. Ihr Computer wird aufgrund des Speicherbedarfs dieses Programms sterben.
Müssen

@ Coder404 Sie haben wahrscheinlich eine Stereo-Wave-Datei oder eine andere Bittiefe.
Jmilloy

3
Für diejenigen, die sich wie ich fragen, was 2s komplementäre Binärdatei ist, finden Sie hier stackoverflow.com/questions/1049722/what-is-2s-complement
Dennis Golomazov

34

Verschiedene Python-Module zum Lesen von WAV:

Es gibt mindestens die folgenden Bibliotheken zum Lesen von Wave-Audiodateien:

Das einfachste Beispiel:

Dies ist ein einfaches Beispiel für SoundFile:

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

Format der Ausgabe:

Achtung, die Daten haben nicht immer das gleiche Format, das von der Bibliothek abhängt. Zum Beispiel:

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)

Ausgabe:

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]

SoundFile- und Audiolab-Rückgabe schwebt zwischen -1 und 1 (wie bei matab ist dies die Konvention für Audiosignale). Scipy- und Wave-Return-Ganzzahlen, die Sie entsprechend der Anzahl der Codierungsbits in Floats konvertieren können, zum Beispiel:

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 

14

IMHO ist SoundFile der einfachste Weg, Audiodaten aus einer Sounddatei in ein NumPy-Array zu übertragen :

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

Dies unterstützt auch sofort einsatzbereite 24-Bit-Dateien.

Es sind viele Sounddateibibliotheken verfügbar. Ich habe eine Übersicht geschrieben, in der Sie einige Vor- und Nachteile sehen können. Es enthält auch eine Seite, auf der erklärt wird, wie eine 24-Bit-WAV-Datei mit dem waveModul gelesen wird .


Hinweis: soundfile.read () normalisiert sich um 2 ^ (n_bits - 1) wie im Beispiel scipy.io.wavfile von Sandoval
Quetzalcoatl

9

Sie können dies mit dem Modul scikits.audiolab erreichen . Für die Funktion sind NumPy und SciPy sowie libsndfile erforderlich.

Beachten Sie, dass ich es nur unter Ubunutu und nicht unter OSX zum Laufen bringen konnte.

from scikits.audiolab import wavread

filename = "testfile.wav"

data, sample_frequency,encoding = wavread(filename)

Jetzt haben Sie die WAV-Daten


scikits.audiolabwurde seit 2010 nicht aktualisiert und es ist wahrscheinlich nur Python 2.
Boris

4

Wenn Sie ein Audio Block für Block verarbeiten möchten, sind einige der angegebenen Lösungen in dem Sinne ziemlich schrecklich, dass sie das Laden des gesamten Audios in den Speicher implizieren, was zu vielen Cache-Fehlern führt und Ihr Programm verlangsamt. Python-Wavefile bietet einige Python-Konstrukte für die blockweise Verarbeitung von NumPy mithilfe einer effizienten und transparenten Blockverwaltung mithilfe von Generatoren. Andere pythonische Besonderheiten sind der Kontextmanager für Dateien, Metadaten als Eigenschaften ... und wenn Sie die gesamte Dateischnittstelle möchten, weil Sie einen schnellen Prototyp entwickeln und sich nicht um die Effizienz kümmern, ist die gesamte Dateischnittstelle immer noch vorhanden.

Ein einfaches Beispiel für die Verarbeitung wäre:

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)

In diesem Beispiel wird derselbe Block zum Lesen der gesamten Datei verwendet, selbst im Fall des letzten Blocks, der normalerweise kleiner als die erforderliche Größe ist. In diesem Fall erhalten Sie ein Stück des Blocks. Vertrauen Sie also der zurückgegebenen Blocklänge, anstatt eine fest codierte 512-Größe für die weitere Verarbeitung zu verwenden.



1

Ich musste eine 1-Kanal-24-Bit-WAV-Datei lesen. Der obige Beitrag von Nak war sehr nützlich. Wie oben von basj erwähnt, ist 24-Bit jedoch nicht einfach. Ich habe es endlich mit dem folgenden Snippet zum Laufen gebracht:

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

Eine zusätzliche Skalierung ist erforderlich, wenn Sie Ergebnisse zwischen -1 und +1 benötigen. Vielleicht finden einige von Ihnen das nützlich


0

Wenn es sich nur um zwei Dateien handelt und die Abtastrate sehr hoch ist, können Sie sie einfach verschachteln.

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)

0

Sie können auch eine einfache import wavioBibliothek verwenden. Sie benötigen auch einige Grundkenntnisse des Klangs.


0

PyDub ( http://pydub.com/ ) wurde nicht erwähnt und das sollte behoben werden. IMO ist dies die derzeit umfassendste Bibliothek zum Lesen von Audiodateien in Python, allerdings nicht ohne Fehler. Lesen einer WAV-Datei:

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. In diesem Beispiel geht es um das Lesen einer WAV-Datei, aber PyDub kann viele verschiedene Formate sofort verarbeiten. Die Einschränkung ist, dass es sowohl auf nativer Python-WAV-Unterstützung als auch auf ffmpeg basiert. Daher muss ffmpeg installiert sein und viele der pydub-Funktionen hängen von der ffmpeg-Version ab. Wenn ffmpeg das kann, kann es normalerweise auch pydub (was ziemlich mächtig ist).

Haftungsausschluss: Ich bin nicht mit dem Projekt verbunden, aber ich bin ein starker Benutzer.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.