107

我需要分析写在 .wav 文件中的声音。为此,我需要将此文件转换为一组数字(例如数组)。我想我需要使用wave包。但是,我不知道它是如何工作的。例如,我做了以下事情:

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

由于此代码,我希望将声压视为时间的函数。相比之下,我看到了很多奇怪的、神秘的符号(不是十六进制数字)。任何人都可以,请,帮助我吗?

4

13 回答 13

133

根据文档scipy.io.wavfile.read(somefile)返回两个项目的元组:第一个是每秒样本的采样率,第二个是一个numpy数组,其中包含从文件中读取的所有数据:

from scipy.io import wavfile
samplerate, data = wavfile.read('./output/audio.wav')
于 2010-01-13T23:44:48.550 回答
64

使用该struct模块,您可以获取波形帧(在 -32768 和 32767(即和)之间的2 的互补二进制中。这读取一个 MONO、16 位、WAVE 文件。我发现这个网页在制定这个方面非常有用:0x80000x7FFF

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

此片段读取 1 帧。要读取多于一帧(例如 13 帧),请使用

wavedata = wavefile.readframes(13)
data = struct.unpack("<13h", wavedata)
于 2011-03-12T07:21:08.023 回答
39

读取 wav 的不同 Python 模块:

至少有以下这些库来读取波形音频文件:

最简单的例子:

这是一个使用 SoundFile 的简单示例:

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

输出格式:

警告,数据并不总是相同的格式,这取决于库。例如:

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)

输出:

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 和 Audiolab 返回介于 -1 和 1 之间的浮点数(就像 matab 一样,这是音频信号的约定)。scipy和wave返回整数,可以根据编码的位数转换成浮点数,例如:

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 
于 2014-11-03T14:13:58.797 回答
17

恕我直言,从声音文件获取音频数据到 NumPy 数组的最简单方法是SoundFile

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

这也支持开箱即用的 24 位文件。

有许多可用的声音文件库,我写了一个概述,您可以在其中看到一些优点和缺点。它还包含一个页面,解释如何使用模块读取 24 位 wav 文件wave

于 2015-09-17T12:09:43.277 回答
9

您可以使用scikits.audiolab模块完成此操作。它需要 NumPy 和 SciPy 才能运行,还需要 libsndfile。

请注意,我只能让它在 Ubunutu 上运行,而不是在 OSX 上运行。

from scikits.audiolab import wavread

filename = "testfile.wav"

data, sample_frequency,encoding = wavread(filename)

现在你有了 wav 数据

于 2011-06-17T22:10:32.073 回答
5

如果您想逐块处理音频,则某些给定的解决方案非常糟糕,因为它们意味着将整个音频加载到内存中会产生许多缓存未命中并减慢您的程序。python-wavefile提供了一些 pythonic 结构,通过生成器使用高效和透明的块管理来进行 NumPy 逐块处理。其他 pythonic 细节是文件的上下文管理器,元数据作为属性......如果你想要整个文件界面,因为你正在开发一个快速原型并且你不关心效率,整个文件界面仍然存在。

一个简单的处理示例是:

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)

该示例重用同一个块来读取整个文件,即使在最后一个块通常小于所需大小的情况下也是如此。在这种情况下,您会得到一块块。因此,请相信返回的块长度,而不是使用硬编码的 512 大小进行任何进一步的处理。

于 2014-09-16T09:54:36.253 回答
2

如果您要对波形数据执行传输,那么也许您应该使用SciPy,特别是scipy.io.wavfile.

于 2010-01-13T22:11:21.150 回答
1

我需要读取一个 1 通道 24 位 WAV 文件。Nak上面的帖子非常有用。但是,正如上面提到的basj 24-bit 并不简单。我终于使用以下代码段让它工作了:

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 和 +1 之间的结果,则需要进行一些额外的缩放。也许你们中的一些人可能会觉得这很有用

于 2015-06-14T17:01:48.907 回答
0

如果它只有两个文件并且采样率非常高,则可以将它们交错。

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)
于 2013-08-23T16:51:36.263 回答
0

亲爱的,据我了解您在寻找什么,您正在进入一个称为数字信号处理 (DSP) 的理论领域。这个工程领域来自对离散时间信号的简单分析到复杂的自适应滤波器。一个好主意是将离散时间信号视为一个向量,其中该向量的每个元素都是原始连续时间信号的采样值。一旦你得到向量形式的样本,你就可以对这个向量应用不同的数字信号技术。

不幸的是,在 Python 上,从音频文件转移到 NumPy 数组向量相当麻烦,您可能会注意到……如果您不崇拜一种编程语言,我强烈建议您尝试 MatLab/Octave。Matlab 使从文件中访问样本变得简单。audioread()为您完成这项任务:) 还有很多专门为 DSP 设计的工具箱。

不过,如果您真的打算为此进入 Python,我将逐步指导您。


1. 获取样品

从文件中获取样本的最简单方法.wav是:

from scipy.io import wavfile

sampling_rate, samples = wavfile.read(f'/path/to/file.wav')


或者,您可以使用waveandstruct包来获取示例:

import numpy as np
import wave, struct

wav_file = wave.open(f'/path/to/file.wav', 'rb')
# from .wav file to binary data in hexadecimal
binary_data = wav_file.readframes(wav_file.getnframes())
# from binary file to samples
s = np.array(struct.unpack('{n}h'.format(n=wav_file.getnframes()*wav_file.getnchannels()), binary_data))

回答你的问题:binary_data是一个bytes对象,它不是人类可读的,只能对机器有意义。您可以验证此语句键入type(binary_data)。如果你真的想了解更多关于这群奇怪的字符,点击这里

如果您的音频是立体声的(即有 2 个通道),您可以重塑此信号以实现与使用scipy.io

s_like_scipy = s.reshape(-1, wav_file.getnchannels())

每一列都是一个香奈儿。无论哪种方式,从.wav文件中获得的样本都可用于绘制和理解信号的时间行为。

在这两种备选方案中,从文件中获得的样本都以线性脉冲编码调制 (LPCM)的形式表示


2. 对音频样本进行数字信号处理

我会把这部分留给你 :) 但这是一本带你了解 DSP 的好书。不幸的是,我不知道关于 Python 的好书,它们通常是可怕的书......但不用担心,只要你使用任何编程语言,该理论都可以以相同的方式应用。

不管你拿起什么书,坚持读经典作者,比如 Proakis、Oppenheim 等等……不要在意他们使用的语言编程。有关使用 Python 进行音频 DPS 的更实用指南,请参阅此页面。

3.播放过滤后的音频样本

import pyaudio

p = pyaudio.PyAudio()
stream = p.open(format = p.get_format_from_width(wav_file.getsampwidth()),
                channels = wav_file.getnchannels(),
                rate = wav_file.getframerate(),
                output = True)
# from samples to the new binary file
new_binary_data = struct.pack('{}h'.format(len(s)), *s)
stream.write(new_binary_data)

其中wav_file.getsampwidth()是每个样本的字节数,wav_file.getframerate()是采样率。只需使用输入音频的相同参数即可。


4. 将结果保存在新.wav文件中

wav_file=wave.open('/phat/to/new_file.wav', 'w')

wav_file.setparams((nchannels, sampwidth, sampling_rate, nframes, "NONE", "not compressed"))

for sample in s:
   wav_file.writeframes(struct.pack('h', int(sample)))

其中nchannels是通道数,sampwidth是每个样本的字节数,sampling_rate是采样率,nframes是样本总数。

于 2022-02-09T19:46:41.980 回答
0

PyDub ( http://pydub.com/ ) 没有被提及,应该修复。IMO 这是目前在 Python 中读取音频文件的最全面的库,尽管并非没有缺点。读取 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。该示例是关于读取 wav 文件的,但 PyDub 可以处理许多开箱即用的各种格式。需要注意的是,它基于原生 Python wav 支持和 ffmpeg,因此您必须安装 ffmpeg 并且许多 pydub 功能依赖于 ffmpeg 版本。通常如果ffmpeg可以做到,那么pydub也可以(相当强大)。

非免责声明:我与项目无关,但我是重度用户。

于 2020-04-22T11:07:39.683 回答
0

这是一个使用内置 wave 模块 [1] 的 Python 3 解决方案,适用于 n 个通道和 8、16、24...位。

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

您可以将结果转换为 NumPy 数组。

import numpy as np

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

请注意,我试图让它可读而不是快速。我发现一次读取所有数据的速度几乎快了 2 倍。例如

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-soundfile大约快 2 个数量级(使用纯 CPython 很难达到这个速度)。

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

于 2020-12-20T09:32:18.540 回答
-1

你也可以使用简单的import wavio库你还需要有一些基本的声音知识。

于 2018-01-27T05:50:18.233 回答