Preciso analisar o som escrito em um arquivo .wav. Para isso preciso transformar esse arquivo em um conjunto de números (arrays, por exemplo). Acho que preciso usar o pacote de ondas. No entanto, não sei exatamente como funciona. Por exemplo, eu fiz o seguinte:
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 desse código, esperava ver a pressão sonora em função do tempo. Em contraste, vejo muitos símbolos estranhos e misteriosos (que não são números hexadecimais). Alguém pode, por favor, me ajudar com isso?
data
é uma matriz numpy 2-D, portanto,data.shape
retorna uma tupla de (num_samples, num_channels)Usando o
struct
módulo , você pode pegar os quadros de onda (que estão no binário complementar de 2 entre -32768 e 32767 (ou seja,0x8000
e0x7FFF
). Isso lê um arquivo MONO, 16-BIT, WAVE. Achei esta página da Web bastante útil para formular isso: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 trecho lê 1 quadro. Para ler mais de um quadro (por exemplo, 13), use
wavedata = wavefile.readframes(13) data = struct.unpack("<13h", wavedata)
fonte
Módulos Python diferentes para ler wav:
Existem pelo menos as seguintes bibliotecas para ler arquivos de áudio wave:
O exemplo mais simples:
Este é um exemplo simples com SoundFile:
import soundfile as sf data, samplerate = sf.read('existing_file.wav')
Formato da saída:
Atenção, os dados nem sempre estão no mesmo formato, isso depende da biblioteca. Por exemplo:
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)
Resultado:
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]
O retorno de SoundFile e Audiolab flutua entre -1 e 1 (como o matab, que é a convenção para sinais de áudio). Scipy e números inteiros de retorno de onda, que você pode converter em flutuantes de acordo com o número de bits de codificação, por exemplo:
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
fonte
IMHO, a maneira mais fácil de obter dados de áudio de um arquivo de som em uma matriz NumPy é SoundFile :
import soundfile as sf data, fs = sf.read('/usr/share/sounds/ekiga/voicemail.wav')
Isso também oferece suporte a arquivos de 24 bits prontos para uso.
Existem muitas bibliotecas de arquivos de som disponíveis, eu escrevi uma visão geral onde você pode ver alguns prós e contras. Ele também apresenta uma página que explica como ler um arquivo wav de 24 bits com o
wave
módulo .fonte
Você pode fazer isso usando o módulo scikits.audiolab . Requer o NumPy e o SciPy para funcionar, e também o libsndfile.
Note, eu só consegui fazer funcionar no Ubunutu e não no OSX.
from scikits.audiolab import wavread filename = "testfile.wav" data, sample_frequency,encoding = wavread(filename)
Agora você tem os dados wav
fonte
scikits.audiolab
não foi atualizado desde 2010 e provavelmente é apenas o Python 2.Se você quiser processar um áudio bloco por bloco, algumas das soluções fornecidas são bastante ruins no sentido de que implicam carregar todo o áudio na memória, produzindo muitos erros de cache e tornando o programa lento. python-wavefile fornece algumas construções pythônicas para fazer o processamento bloco a bloco do NumPy usando gerenciamento de bloco eficiente e transparente por meio de geradores. Outras sutilezas pythônicas são o gerenciador de contexto para arquivos, metadados como propriedades ... e se você quiser toda a interface do arquivo, porque você está desenvolvendo um protótipo rápido e não se preocupa com a eficiência, toda a interface do arquivo ainda está lá.
Um exemplo simples de processamento seria:
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)
O exemplo reutiliza o mesmo bloco para ler todo o arquivo, mesmo no caso do último bloco que geralmente é menor que o tamanho necessário. Neste caso, você obtém uma fatia do bloco. Portanto, confie no comprimento do bloco retornado em vez de usar um tamanho 512 codificado para qualquer processamento posterior.
fonte
Se você for realizar transferências nos dados da forma de onda, talvez deva usar o SciPy , especificamente
scipy.io.wavfile
.fonte
Eu precisava ler um arquivo WAV de 24 bits de 1 canal. O post acima de Nak foi muito útil. No entanto, conforme mencionado acima por basj 24 bits não é simples. Finalmente consegui fazer funcionar usando o seguinte snippet:
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
Algum escalonamento adicional é necessário se você precisar de resultados entre -1 e +1. Talvez alguns de vocês possam achar isso útil
fonte
se forem apenas dois arquivos e a taxa de amostragem for significativamente alta, você pode apenas intercalá-los.
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)
fonte
Você também pode usar uma
import wavio
biblioteca simples. Você também precisa ter alguns conhecimentos básicos de som.fonte
PyDub ( http://pydub.com/ ) não foi mencionado e isso deve ser corrigido. IMO, esta é a biblioteca mais abrangente para leitura de arquivos de áudio em Python atualmente, embora tenha seus defeitos. Lendo um arquivo 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. O exemplo é sobre a leitura de um arquivo wav, mas o PyDub pode lidar com vários formatos de fábrica. A ressalva é que ele é baseado no suporte nativo de wav do Python e ffmpeg, então você precisa ter o ffmpeg instalado e muitos dos recursos do pydub dependem da versão do ffmpeg. Normalmente, se o ffmpeg pode fazer isso, o pydub também pode (que é bastante poderoso).
Isenção de responsabilidade: não sou relacionado ao projeto, mas sou um usuário pesado.
fonte
Aqui está uma solução Python 3 usando o módulo de onda embutido [1], que funciona para n canais e 8,16,24 ... bits.
import sys import wave def read_wav(path): with wave.open(path, "rb") as wav: nchannels, sampwidth, framerate, nframes, _, _ = wav.getparams() print(wav.getparams(), "\nBits per sample =", sampwidth * 8) signed = sampwidth > 1 # 8 bit wavs are unsigned byteorder = sys.byteorder # wave module uses sys.byteorder for bytes values = [] # e.g. for stereo, values[i] = [left_val, right_val] for _ in range(nframes): frame = wav.readframes(1) # read next frame channel_vals = [] # mono has 1 channel, stereo 2, etc. for channel in range(nchannels): as_bytes = frame[channel * sampwidth: (channel + 1) * sampwidth] as_int = int.from_bytes(as_bytes, byteorder, signed=signed) channel_vals.append(as_int) values.append(channel_vals) return values, framerate
Você pode transformar o resultado em uma matriz NumPy.
import numpy as np data, rate = read_wav(path) data = np.array(data)
Observe, tentei torná-lo legível em vez de rápido. Descobri que ler todos os dados de uma vez foi quase 2x mais rápido. Por exemplo
with wave.open(path, "rb") as wav: nchannels, sampwidth, framerate, nframes, _, _ = wav.getparams() all_bytes = wav.readframes(-1) framewidth = sampwidth * nchannels frames = (all_bytes[i * framewidth: (i + 1) * framewidth] for i in range(nframes)) for frame in frames: ...
Embora python-soundfile seja cerca de 2 ordens de magnitude mais rápido (difícil aproximar essa velocidade com CPython puro).
[1] https://docs.python.org/3/library/wave.html
fonte