* .Wav dosyalarını Python'da okuma


92

.Wav dosyasında yazılmış sesi analiz etmem gerekiyor. Bunun için bu dosyayı sayı kümesine dönüştürmem gerekiyor (örneğin diziler). Dalga paketini kullanmam gerektiğini düşünüyorum. Ancak tam olarak nasıl çalıştığını bilmiyorum. Örneğin şunları yaptım:

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

Bu kodun bir sonucu olarak, ses basıncını zamanın bir işlevi olarak görmeyi bekliyordum. Aksine, (onaltılık sayılar olmayan) birçok garip, gizemli sembol görüyorum. Herhangi biri bana yardım edebilir mi?

Yanıtlar:


114

Ortalama belgeleri , scipy.io.wavfile.read(somefile)iki öğe bir demet verir: ilk örnekleme hızı saniyede örneklerde, ikinci bir olan numpyveri dosyası okuma tüm dizi:

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

Diğer biçimleri açmak için bunu komut satırı dönüştürme araçlarıyla birleştirebilirsiniz.
endolith

11
Yine de kanal sayısından ciddi şekilde yoksun. Kanalların sayısını bilmeden sesle nasıl çalışacaksınız?
bastibe

bilgisayarımda bazı garip yapı paketini açma hataları attı. Sanırım aşağıda kullanılan struct.unpack ('<h', data) nak yerine struct.unpack ('<i', data) kullanıyor.
Alex S

1
Bu kütüphane çalışıyor mu? Bir dizi problemle karşılaşıyorum: scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / samples / data / house_lo.wav') -> Veri yok. scipy.io.wavfile.read ('/ usr / lib / python2.7 / dist-packages / pygame / samples / data / secosmic_lo.wav') -> ZeroDivisionError: tamsayı bölme veya sıfıra göre modulo
Finn Årup Nielsen

7
@bastibe data2 boyutlu bir uyuşuk dizidir, bu nedenle data.shapebir demet (num_samples, num_channels) döndürür
hobs

63

structModülü kullanarak, dalga çerçevelerini alabilirsiniz ( 2'nin -32768 ile 32767 arasındaki tamamlayıcı ikili (yani 0x8000ve 0x7FFF). Bu bir MONO, 16-BIT, WAVE dosyası okuyor. Bu web sayfasını bunu formüle etmede oldukça faydalı buldum :

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

Bu pasaj 1 kare okur. Birden fazla çerçeve okumak için (ör. 13),

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

2
24 bit stereo dosyalar nasıl kullanılır?
2013

14
bu bana şu hatayı veriyor: "struct.error: unpack, uzunluğu 2 olan bir dize argümanı gerektiriyor"
Coder404

1
Bu kod parçasını çok büyük bir ses dosyasıyla çalıştırırsanız. Bilgisayarınız, bu programın bellek ihtiyacı nedeniyle ölecek. Büyük ses dosyası için ses dosyasını bloklar halinde işlemek gerekiyor
ArthurLambert

@ Coder404 Muhtemelen bir stereo wave dosyanız veya farklı bir bit derinliğiniz var.
jmilloy

3
Benim gibi 2'nin tamamlayıcı ikiliğinin ne olduğunu merak edenler için, buraya bakın stackoverflow.com/questions/1049722/what-is-2s-complement
Dennis Golomazov

34

Wav okumak için farklı Python modülleri:

Wave ses dosyalarını okumak için en azından aşağıdaki kitaplıklar vardır:

En basit örnek:

Bu, SoundFile ile basit bir örnektir:

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

Çıktının formatı:

Uyarı, veriler her zaman aynı formatta değildir, bu kitaplığa bağlıdır. Örneğin:

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)

Çıktı:

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 ve Audiolab dönüşü -1 ile 1 arasında yüzer (matab'ın yaptığı gibi, bu ses sinyalleri için bir kuraldır). Kodlama bitlerinin sayısına göre kayan sayılara dönüştürebileceğiniz Scipy ve wave return tamsayıları, örneğin:

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, ses verilerini bir ses dosyasından NumPy dizisine almanın en kolay yolu SoundFile'dır :

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

Bu aynı zamanda 24 bitlik dosyaları kutudan çıkarır.

Kullanılabilir birçok ses dosyası kitaplığı var, birkaç artı ve eksiyi görebileceğiniz bir genel bakış yazdım . Ayrıca modülle birlikte 24 bitlik bir wav dosyasının nasıl okunacağınıwave açıklayan bir sayfa da içerir .


Not: soundfile.read () sandoval'ın scipy.io.wavfile örneğinde olduğu gibi 2 ^ (n_bits - 1) normalize eder
Quetzalcoatl

9

Bunu scikits.audiolab modülünü kullanarak gerçekleştirebilirsiniz . Çalışması için NumPy ve SciPy'nin yanı sıra libsndfile gerektirir.

Not, ben sadece Ubunutu üzerinde çalışabildim, OSX üzerinde çalışmadım.

from scikits.audiolab import wavread

filename = "testfile.wav"

data, sample_frequency,encoding = wavread(filename)

Şimdi wav verilerine sahipsiniz


scikits.audiolab2010'dan beri güncellenmedi ve muhtemelen yalnızca Python 2'dir.
Boris

4

Bir sesi blok blok işlemek istiyorsanız, verilen çözümlerden bazıları, tüm sesi belleğe yükleyerek birçok önbellek kaçırma ve programınızı yavaşlatma anlamında oldukça kötüdür. python-wavefile , üreteçler aracılığıyla verimli ve şeffaf blok yönetimi kullanarak NumPy blok-blok işleme yapmak için bazı pitonik yapılar sağlar. Diğer pitonik nitelikler dosyalar için bağlam yöneticisi, meta veriler özellikler olarak ... ve tüm dosya arayüzünü istiyorsanız, çünkü hızlı bir prototip geliştiriyorsunuz ve verimliliği önemsemiyorsunuz, tüm dosya arayüzü hala oradadır.

Basit bir işleme örneği şöyle olabilir:

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)

Örnek, genellikle gerekli boyuttan daha küçük olan son blok durumunda bile tüm dosyayı okumak için aynı bloğu yeniden kullanır. Bu durumda bloktan bir dilim alırsınız. Bu nedenle, sonraki işlemler için sabit kodlanmış 512 boyutu kullanmak yerine döndürülen blok uzunluğuna güvenin.


1

Dalga formu verileri üzerinde transferler gerçekleştirecekseniz, belki de özellikle SciPy kullanmalısınız scipy.io.wavfile.


2
TAMAM. SciPy'yi yeni yükledim ancak scipy.io.wavfile kullanımına dair herhangi bir örnek bulamıyorum.
Roman

6
İşlerin nasıl yürüdüğünü anlamak için interaktif tercüman gibisi yoktur! Hırslı ol!
Ignacio Vazquez-Abrams

1

1 kanallı 24 bit WAV dosyasını okumam gerekiyordu. Nak'ın yukarıdaki yazısı çok faydalı oldu. Ancak yukarıda basj tarafından belirtildiği gibi 24-bit basit değildir. Sonunda aşağıdaki pasajı kullanarak çalıştırdım:

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

-1 ile +1 arasında sonuçlara ihtiyacınız varsa bazı ek ölçeklendirme gerekir. Belki bazılarınız bunu yararlı bulabilir


0

eğer sadece iki dosya ise ve örnekleme oranı önemli ölçüde yüksekse, bunları araya ekleyebilirsiniz.

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

Basit bir import waviokitaplığı da kullanabilirsiniz u ayrıca sesle ilgili bazı temel bilgilere sahip olmanız gerekir.


0

PyDub'dan ( http://pydub.com/ ) bahsedilmemiştir ve bu düzeltilmelidir. IMO Bu, hatasız olmasa da, şu anda Python'da ses dosyalarını okumak için en kapsamlı kitaplıktır. Bir wav dosyasını okumak:

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. Örnek bir wav dosyasını okumakla ilgilidir, ancak PyDub birçok farklı formatı kutudan çıkarabilir. Uyarı, hem yerel Python wav desteğine hem de ffmpeg'e dayanmasıdır, bu nedenle ffmpeg'in yüklü olması gerekir ve birçok pydub özelliği ffmpeg sürümüne dayanır. Genellikle ffmpeg bunu yapabiliyorsa, pydub da yapabilir (ki bu oldukça güçlüdür).

Sorumluluk reddi beyanı: Proje ile ilgili değilim, ancak yoğun bir kullanıcıyım.


0

Burada n kanal ve 8,16,24 ... bit için çalışan yerleşik dalga modülünü [1] kullanan bir Python 3 çözümü.

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

Sonucu bir NumPy dizisine dönüştürebilirsiniz.

import numpy as np

data, rate = read_wav(path)
data = np.array(data)

Not, hızlı yerine okunabilir hale getirmeye çalıştım. Tüm verileri aynı anda okumanın neredeyse 2 kat daha hızlı olduğunu öğrendim. Örneğin

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:
    ...

Python ses dosyası kabaca 2 kat daha hızlı olmasına rağmen (bu hıza saf CPython ile yaklaşmak zordur).

[1] https://docs.python.org/3/library/wave.html

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.