Leyendo archivos * .wav en Python

90

Necesito analizar el sonido escrito en un archivo .wav. Para eso necesito transformar este archivo en un conjunto de números (matrices, por ejemplo). Creo que necesito usar el paquete wave. Sin embargo, no sé exactamente cómo funciona. Por ejemplo, hice lo siguiente:

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

Como resultado de este código, esperaba ver la presión del sonido como función del tiempo. En contraste, veo muchos símbolos extraños y misteriosos (que no son números hexadecimales). ¿Alguien, por favor, puede ayudarme con eso?

romano
fuente

Respuestas:

109

Según la documentación , scipy.io.wavfile.read(somefile)devuelve una tupla de dos elementos: el primero es la frecuencia de muestreo en muestras por segundo, el segundo es una numpymatriz con todos los datos leídos del archivo:

from scipy.io import wavfile
samplerate, data = wavfile.read('./output/audio.wav')
Alex Martelli
fuente
Puede combinar esto con herramientas de conversión de línea de comandos para abrir otros formatos.
endolito
11
Sin embargo, carece seriamente de la cantidad de canales. ¿Cómo se supone que va a trabajar con audio sin saber la cantidad de canales?
Bastibe
arroja algunos errores extraños de descompresión de estructuras en mi computadora. Creo que está usando struct.unpack ('<i', data) en lugar de struct.unpack ('<h', data) nak que se usa a continuación.
Alex S
1
¿Funciona esta biblioteca? Me encuentro con varios problemas: scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / examples / data / house_lo.wav') -> Sin datos. scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / examples / data / secosmic_lo.wav') -> ZeroDivisionError: división entera o módulo por cero
Finn Årup Nielsen
6
@bastibe dataes una matriz numpy 2-D de modo data.shapedevuelve una tupla de (num_samples, num_channels)
Placas de cocción
63

Usando el structmódulo , puede tomar los marcos de onda (que están en el binario complementario de 2 entre -32768 y 32767 (es decir, 0x8000y 0x7FFF). Esto lee un archivo MONO, 16-BIT, WAVE. Encontré esta página web bastante útil para formular esto:

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

Este fragmento lee 1 fotograma. Para leer más de un cuadro (por ejemplo, 13), utilice

wavedata = wavefile.readframes(13)
data = struct.unpack("<13h", wavedata)
nak
fuente
2
¿Cómo manejar archivos estéreo de 24 bits?
Basj
14
esto me da el error: "struct.error: unpack requiere un argumento de cadena de longitud 2"
Coder404
1
Si ejecuta este fragmento de código con un archivo de audio muy grande. Su computadora morirá debido a la necesidad de memoria de este programa. Necesidad de procesar archivo de audio por bloque para un archivo de audio grande
ArthurLambert
@ Coder404 Probablemente tenga un archivo de onda estéreo o una profundidad de bits diferente.
jmilloy
3
Para aquellos que, como yo, se preguntan qué es el binario complementario 2s, consulte aquí stackoverflow.com/questions/1049722/what-is-2s-complement
Dennis Golomazov
34

Diferentes módulos de Python para leer wav:

Existen al menos las siguientes bibliotecas para leer archivos de audio wave:

El ejemplo más simple:

Este es un ejemplo simple con SoundFile:

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

Formato de la salida:

Advertencia, los datos no siempre están en el mismo formato, eso depende de la biblioteca. Por ejemplo:

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)

Salida:

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 y Audiolab devuelven flota entre -1 y 1 (como hace matab, esa es la convención para las señales de audio). Scipy y wave devuelven enteros, que puede convertir en flotantes de acuerdo con la cantidad de bits de codificación, por ejemplo:

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
fuente
14

En mi humilde opinión, la forma más fácil de obtener datos de audio de un archivo de sonido en una matriz NumPy es SoundFile :

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

Esto también admite archivos de 24 bits listos para usar.

Hay muchas bibliotecas de archivos de sonido disponibles, he escrito una descripción general donde se pueden ver algunos pros y contras. También presenta una página que explica cómo leer un archivo wav de 24 bits con el wavemódulo .

Matías
fuente
Nota: soundfile.read () se normaliza por 2 ^ (n_bits - 1) como en el ejemplo de scipy.io.wavfile de sandoval
Quetzalcoatl
9

Puede lograr esto usando el módulo scikits.audiolab . Requiere NumPy y SciPy para funcionar, y también libsndfile.

Tenga en cuenta que solo pude hacer que funcione en Ubunutu y no en OSX.

from scikits.audiolab import wavread

filename = "testfile.wav"

data, sample_frequency,encoding = wavread(filename)

Ahora tienes los datos wav

ch3rryc0ke
fuente
scikits.audiolabno se ha actualizado desde 2010 y probablemente sea solo Python 2.
Boris
4

Si desea procesar un audio bloque por bloque, algunas de las soluciones dadas son bastante horribles en el sentido de que implican cargar todo el audio en la memoria, lo que produce muchas pérdidas de caché y ralentiza su programa. python-wavefile proporciona algunas construcciones pitónicas para realizar el procesamiento bloque por bloque de NumPy utilizando una gestión de bloques eficiente y transparente por medio de generadores. Otras sutilezas de Pythonic son el administrador de contexto para archivos, metadatos como propiedades ... y si desea la interfaz de archivo completa, porque está desarrollando un prototipo rápido y no le importa la eficiencia, la interfaz de archivo completa todavía está ahí.

Un ejemplo simple de procesamiento sería:

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)

El ejemplo reutiliza el mismo bloque para leer todo el archivo, incluso en el caso del último bloque que normalmente es menor que el tamaño requerido. En este caso, obtienes una porción del bloque. Así que confíe en la longitud del bloque devuelta en lugar de usar un tamaño 512 codificado para cualquier procesamiento posterior.

vokimon
fuente
1

Si va a realizar transferencias en los datos de forma de onda, tal vez debería usar SciPy , específicamente scipy.io.wavfile.

Ignacio Vázquez-Abrams
fuente
2
OKAY. Acabo de instalar SciPy pero no puedo encontrar ningún ejemplo del uso de scipy.io.wavfile.
Romano
6
¡Nada como el intérprete interactivo para descubrir cómo funcionan las cosas! ¡Ser ambicioso!
Ignacio Vazquez-Abrams
1

Necesitaba leer un archivo WAV de 1 canal y 24 bits. La publicación anterior de Nak fue muy útil. Sin embargo, como se mencionó anteriormente por basj 24-bit no es sencillo. Finalmente lo hice funcionar usando el siguiente fragmento:

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

Se requiere una escala adicional si necesita resultados entre -1 y +1. Tal vez algunos de ustedes puedan encontrar esto útil

ProgJos
fuente
0

si son solo dos archivos y la frecuencia de muestreo es significativamente alta, puede simplemente intercalarlos.

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
fuente
0

También puede usar una import waviobiblioteca simple. También necesita tener algunos conocimientos básicos del sonido.

Yunus
fuente
0

PyDub ( http://pydub.com/ ) no se ha mencionado y eso debería corregirse . En mi opinión, esta es la biblioteca más completa para leer archivos de audio en Python en este momento, aunque no sin sus fallas. Leyendo un archivo 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/

PD. El ejemplo trata sobre la lectura de un archivo wav, pero PyDub puede manejar muchos formatos distintos desde el primer momento. La advertencia es que se basa tanto en el soporte nativo de Python wav como en ffmpeg, por lo que debe tener instalado ffmpeg y muchas de las capacidades de pydub dependen de la versión ffmpeg. Por lo general, si ffmpeg puede hacerlo, también puede hacerlo pydub (que es bastante poderoso).

No descargo de responsabilidad: no estoy relacionado con el proyecto, pero soy un gran usuario.

wanaryytel
fuente