Lettura di file * .wav in Python


90

Ho bisogno di analizzare il suono scritto in un file .wav. Per questo ho bisogno di trasformare questo file in un insieme di numeri (array, per esempio). Penso di aver bisogno di usare il pacchetto wave. Tuttavia, non so esattamente come funzioni. Ad esempio, ho fatto quanto segue:

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

Come risultato di questo codice mi aspettavo di vedere la pressione sonora come funzione del tempo. Al contrario, vedo molti simboli strani e misteriosi (che non sono numeri esadecimali). Qualcuno può, per favore, aiutarmi con quello?

Risposte:


109

Secondo la documentazione , scipy.io.wavfile.read(somefile)restituisce una tupla di due elementi: il primo è la frequenza di campionamento in campioni al secondo, il secondo è un numpyarray con tutti i dati letti dal file:

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

Puoi combinarlo con gli strumenti di conversione della riga di comando per aprire altri formati.
endolith

11
Tuttavia manca seriamente il numero di canali. Come dovresti lavorare con l'audio senza conoscere il numero di canali?
bastibe

genera alcuni strani errori di decompressione della struttura sul mio computer. Penso che stia usando struct.unpack ('<i', data) invece dello struct.unpack ('<h', data) nak usato di seguito.
Alex S

1
Questa libreria funziona? Mi imbatto in una serie di problemi: scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / examples / data / house_lo.wav') -> Nessun dato. scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / examples / data / secosmic_lo.wav') -> ZeroDivisionError: divisione intera o modulo per zero
Finn Årup Nielsen

6
@bastibe dataè una matrice NumPy 2-D in modo data.shaperitorna una tupla di (num_samples, num_channels)
piani cottura

63

Usando il structmodulo , puoi prendere i frame wave (che sono nel binario complementare di 2 tra -32768 e 32767 (cioè 0x8000e 0x7FFF). Questo legge un file MONO, 16-BIT, WAVE. Ho trovato questa pagina web molto utile per formulare questo:

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

Questo frammento legge 1 frame. Per leggere più di un frame (ad esempio, 13), utilizzare

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

2
come gestire i file stereo a 24 bit?
Basj

14
questo mi dà l'errore: "struct.error: unpack richiede un argomento stringa di lunghezza 2"
Coder404

1
Se esegui questo pezzo di codice con un file audio molto grande. Il tuo computer morirà a causa della memoria richiesta da questo programma. È necessario elaborare file audio per blocco per file audio di grandi dimensioni
ArthurLambert

@ Coder404 Probabilmente hai un file wave stereo o una diversa profondità di bit.
jmilloy

3
Per chi, come me, si chiedono che cosa è 2s binario complementare, vedi qui stackoverflow.com/questions/1049722/what-is-2s-complement
Dennis Golomazov

34

Diversi moduli Python per leggere wav:

Ci sono almeno queste seguenti librerie per leggere i file audio wave:

L'esempio più semplice:

Questo è un semplice esempio con SoundFile:

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

Formato dell'output:

Attenzione, i dati non sono sempre nello stesso formato, dipende dalla libreria. Per esempio:

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)

Produzione:

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 e Audiolab restituiscono float tra -1 e 1 (come fa matab, che è la convenzione per i segnali audio). Scipy e wave restituiscono numeri interi, che puoi convertire in float in base al numero di bit di codifica, ad esempio:

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, il modo più semplice per ottenere dati audio da un file audio in un array NumPy è SoundFile :

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

Questo supporta anche file a 24 bit pronti all'uso.

Sono disponibili molte librerie di file audio, ho scritto una panoramica in cui puoi vedere alcuni pro e contro. Presenta anche una pagina che spiega come leggere un file wav a 24 bit con il wavemodulo .


Nota: soundfile.read () normalizza di 2 ^ (n_bits - 1) come nell'esempio scipy.io.wavfile di sandoval
Quetzalcoatl

9

Puoi farlo usando il modulo scikits.audiolab . Richiede NumPy e SciPy per funzionare e anche libsndfile.

Nota, sono stato in grado di farlo funzionare solo su Ubunutu e non su OSX.

from scikits.audiolab import wavread

filename = "testfile.wav"

data, sample_frequency,encoding = wavread(filename)

Ora hai i dati wav


scikits.audiolabnon è stato aggiornato dal 2010 ed è probabilmente solo Python 2.
Boris

4

Se vuoi elaborare un audio blocco per blocco, alcune delle soluzioni fornite sono piuttosto orribili nel senso che implicano il caricamento dell'intero audio in memoria producendo molti errori nella cache e rallentando il programma. python-wavefile fornisce alcuni costrutti pitonici per eseguire l'elaborazione blocco per blocco di NumPy utilizzando una gestione dei blocchi efficiente e trasparente per mezzo di generatori. Altre sottigliezze pitoniche sono il gestore di contesto per i file, i metadati come proprietà ... e se vuoi l'intera interfaccia del file, poiché stai sviluppando un prototipo veloce e non ti interessa l'efficienza, l'intera interfaccia del file è ancora lì.

Un semplice esempio di elaborazione potrebbe essere:

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)

L'esempio riutilizza lo stesso blocco per leggere l'intero file, anche nel caso dell'ultimo blocco che solitamente è inferiore alla dimensione richiesta. In questo caso ottieni una fetta del blocco. Quindi fidati della lunghezza del blocco restituito invece di usare una dimensione 512 codificata per qualsiasi ulteriore elaborazione.



1

Avevo bisogno di leggere un file WAV a 24 bit a 1 canale. Il post sopra di Nak è stato molto utile. Tuttavia, come accennato in precedenza da basj a 24 bit non è semplice. Finalmente ho funzionato usando il seguente frammento:

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

È necessario un ridimensionamento aggiuntivo se sono necessari risultati compresi tra -1 e +1. Forse alcuni di voi là fuori potrebbero trovarlo utile


0

se sono solo due file e la frequenza di campionamento è significativamente alta, potresti semplicemente intercalarli.

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

Puoi anche usare una semplice import waviolibreria e devi avere una conoscenza di base del suono.


0

PyDub ( http://pydub.com/ ) non è stato menzionato e dovrebbe essere risolto. IMO questa è la libreria più completa per leggere file audio in Python in questo momento, anche se non senza i suoi difetti. Leggere un file 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. L'esempio riguarda la lettura di un file wav, ma PyDub può gestire molti formati diversi fuori dagli schemi. L'avvertenza è che si basa sia sul supporto wav nativo di Python che su ffmpeg, quindi devi avere ffmpeg installato e molte delle funzionalità di pydub si basano sulla versione ffmpeg. Di solito se ffmpeg può farlo, può farlo anche pydub (che è abbastanza potente).

Non disclaimer: non sono legato al progetto, ma sono un utente pesante.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.