Lecture de fichiers * .wav en Python


90

J'ai besoin d'analyser le son écrit dans un fichier .wav. Pour cela, j'ai besoin de transformer ce fichier en ensemble de nombres (tableaux, par exemple). Je pense que j'ai besoin d'utiliser le package wave. Cependant, je ne sais pas comment cela fonctionne exactement. Par exemple, j'ai fait ce qui suit:

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

À la suite de ce code, je m'attendais à voir la pression acoustique en fonction du temps. En revanche, je vois beaucoup de symboles étranges et mystérieux (qui ne sont pas des nombres hexadécimaux). Quelqu'un peut-il, s'il vous plaît, m'aider avec ça?

Réponses:


109

Selon la documentation , scipy.io.wavfile.read(somefile)renvoie un tuple de deux éléments: le premier est le taux d'échantillonnage en échantillons par seconde, le second est un numpytableau avec toutes les données lues à partir du fichier:

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

Vous pouvez combiner cela avec des outils de conversion de ligne de commande pour ouvrir d'autres formats.
endolith

11
Il manque cependant sérieusement le nombre de canaux. Comment êtes-vous censé travailler avec l'audio sans connaître le nombre de canaux?
bastibe

jette des erreurs de décompression de structure étranges sur mon ordinateur. Je pense qu'il utilise struct.unpack ('<i', data) au lieu du struct.unpack ('<h', data) nak utilisé ci-dessous.
Alex S

1
Cette bibliothèque fonctionne-t-elle? Je rencontre un certain nombre de problèmes: scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / examples / data / house_lo.wav') -> Aucune donnée. scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / examples / data / secosmic_lo.wav') -> ZeroDivisionError: division entière ou modulo par zéro
Finn Årup Nielsen

6
@bastibe dataest une matrice de numpy 2-D de sorte data.shaperetourne un tuple de (num_samples, num_channels)
plaques de cuisson

63

En utilisant le structmodule , vous pouvez prendre les trames d'onde (qui sont dans le binaire complémentaire de 2 entre -32768 et 32767 (c'est-à 0x8000- dire et 0x7FFF). Cela lit un fichier MONO, 16-BIT, WAVE. J'ai trouvé cette page Web très utile pour formuler ceci:

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

Cet extrait de code lit 1 image. Pour lire plus d'une image (par exemple, 13), utilisez

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

2
comment gérer les fichiers stéréo 24 bits?
Basj

14
cela me donne l'erreur: "struct.error: unpack nécessite un argument de chaîne de longueur 2"
Coder404

1
Si vous exécutez ce morceau de code avec un très gros fichier audio. Votre ordinateur sera mort en raison des besoins en mémoire de ce programme. Besoin de traiter un fichier audio par bloc pour un gros fichier audio
ArthurLambert

@ Coder404 Vous avez probablement un fichier wave stéréo ou une profondeur de bits différente.
jmilloy

3
Pour ceux qui, comme moi, se demandent ce qu'est le binaire complémentaire 2s, voir ici stackoverflow.com/questions/1049722/what-is-2s-complement
Dennis Golomazov

34

Différents modules Python pour lire wav:

Il existe au moins ces bibliothèques suivantes pour lire les fichiers audio wave:

L'exemple le plus simple:

Voici un exemple simple avec SoundFile:

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

Format de la sortie:

Attention, les données ne sont pas toujours au même format, cela dépend de la bibliothèque. Par exemple:

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)

Production:

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 et Audiolab renvoient des flotteurs entre -1 et 1 (comme le fait matab, c'est la convention pour les signaux audio). Scipy et wave renvoient des entiers, que vous pouvez convertir en flottants en fonction du nombre de bits d'encodage, par exemple:

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

À mon humble avis , le moyen le plus simple d'obtenir des données audio à partir d'un fichier audio dans un tableau NumPy est SoundFile :

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

Cela prend également en charge les fichiers 24 bits prêts à l'emploi.

Il existe de nombreuses bibliothèques de fichiers audio disponibles, j'ai écrit un aperçu où vous pouvez voir quelques avantages et inconvénients. Il comporte également une page expliquant comment lire un fichier wav 24 bits avec le wavemodule .


Remarque: soundfile.read () normalise par 2 ^ (n_bits - 1) comme dans l'exemple scipy.io.wavfile de sandoval
Quetzalcoatl

9

Vous pouvez accomplir cela en utilisant le scikits.audiolab module . Il nécessite NumPy et SciPy pour fonctionner, ainsi que libsndfile.

Notez que je n'ai pu le faire fonctionner que sur Ubunutu et non sur OSX.

from scikits.audiolab import wavread

filename = "testfile.wav"

data, sample_frequency,encoding = wavread(filename)

Maintenant vous avez les données wav


scikits.audiolabn'a pas été mis à jour depuis 2010 et il s'agit probablement de Python 2 uniquement.
Boris le

4

Si vous souhaitez traiter un bloc audio bloc par bloc, certaines des solutions proposées sont assez horribles dans le sens où elles impliquent de charger tout l'audio en mémoire, produisant de nombreux échecs de cache et ralentissant votre programme. python-wavefile fournit des constructions pythoniques pour effectuer le traitement bloc par bloc NumPy en utilisant une gestion de bloc efficace et transparente au moyen de générateurs. D'autres subtilités pythoniques sont le gestionnaire de contexte pour les fichiers, les métadonnées comme propriétés ... et si vous voulez toute l'interface de fichier, parce que vous développez un prototype rapide et que vous ne vous souciez pas de l'efficacité, toute l'interface de fichier est toujours là.

Un exemple simple de traitement serait:

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'exemple réutilise le même bloc pour lire tout le fichier, même dans le cas du dernier bloc qui est généralement inférieur à la taille requise. Dans ce cas, vous obtenez une tranche du bloc. Faites donc confiance à la longueur de bloc retournée au lieu d'utiliser une taille 512 codée en dur pour tout traitement ultérieur.


1

Si vous souhaitez effectuer des transferts sur les données de forme d'onde, vous devriez peut-être utiliser SciPy , en particulier scipy.io.wavfile.


2
D'ACCORD. Je viens d'installer le SciPy mais je ne trouve aucun exemple d'utilisation de scipy.io.wavfile.
Roman

6
Rien de tel que l'interprète interactif pour comprendre comment les choses fonctionnent! Soit ambitieux!
Ignacio Vazquez-Abrams

1

J'avais besoin de lire un fichier WAV 24 bits à 1 canal. Le message ci-dessus de Nak était très utile. Cependant, comme mentionné ci-dessus par basj 24 bits n'est pas simple. Je l'ai finalement fait fonctionner en utilisant l'extrait de code suivant:

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

Une mise à l'échelle supplémentaire est requise si vous avez besoin de résultats compris entre -1 et +1. Peut-être que certains d'entre vous pourraient trouver cela utile


0

s'il ne s'agit que de deux fichiers et que la fréquence d'échantillonnage est significativement élevée, vous pouvez simplement les entrelacer.

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

Vous pouvez également utiliser une import waviobibliothèque simple. Vous devez également avoir des connaissances de base sur le son.


0

PyDub ( http://pydub.com/ ) n'a pas été mentionné et cela devrait être corrigé. IMO, c'est la bibliothèque la plus complète pour la lecture de fichiers audio en Python à l'heure actuelle, mais pas sans ses défauts. Lire un fichier 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'exemple concerne la lecture d'un fichier wav, mais PyDub peut gérer de nombreux formats différents prêts à l'emploi. La mise en garde est qu'il est basé à la fois sur le support natif de Python wav et ffmpeg, vous devez donc avoir ffmpeg installé et beaucoup de capacités pydub reposent sur la version ffmpeg. Habituellement, si ffmpeg peut le faire, pydub peut aussi le faire (qui est assez puissant).

Non-avertissement: je ne suis pas lié au projet, mais je suis un gros utilisateur.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.