Python3 正确修改wav音频数据
Python3 modifying wav audio data correctly
学习如何修改不同类型的音频文件,.wav, .mp3 ,等等,使用 Python3 使用 wave
模块。具体是.wav文件格式,在这方面针对这个问题。目前,我知道音频格式有 ISO 标准,非常感谢有关此主题的关于 .wav 文件格式的音频标准的任何参考以及旁注。
但就我的问题而言,只需忽略 RIFF、FMT headers,在 [=28= .wav 文件使用 Python3 wave
模块导入。
有没有更高效的方式跳过RIFFheaders,其他容器,直接进入data容器修改其内容?
这个粗略的例子只是将 two-channel 音频 .wav 文件转换为 single-channel 音频 .wav 文件,同时将所有值修改为 (0, 0).
import wave
import struct
# Open Files
inf = wave.open(r"piano2.wav", 'rb')
outf = wave.open(r"output.wav", 'wb')
# Input Parameters
ip = list(inf.getparams())
print('Input Parameters:', ip)
# Example Output: Input Parameters: [2, 2, 48000, 302712, 'NONE', 'not compressed']
# Output Parameters
op = ip[:]
op[0] = 1
outf.setparams(op)
number_of_channels, sample_width, frame_rate, number_of_frames, comp_type, comp_name = ip
format = '<{}h'.format(number_of_channels)
print('# Channels:', format)
# Read >> Second
for index in range(number_of_frames):
frame = inf.readframes(1)
data = struct.unpack(format, frame)
# Here, I change data to (0, 0), testing purposes
print('Before Audio Data:', data)
print('After Modifying Audio Data', (0, 0))
# Change Audio Data
data = (0, 0)
value = data[0]
value = (value * 2) // 3
outf.writeframes(struct.pack('<h', value))
# Close In File
inf.close()
# Close Out File
outf.close()
如果只是修改.wav文件的数据段,是否有更好的做法或参考material?
- 假设您想在特定时间戳中逐字添加声音,这对我的问题来说是更合适的结果。
性能比较
让我们来看看读取 WAVE 文件的前 3 种方法。
最慢的一波模块
正如您可能已经注意到的那样,wave
模块可能非常慢。考虑这段代码:
import wave
import struct
wavefile = wave.open('your.wav', 'r') # check e.g. freesound.org for samples
length = wavefile.getnframes()
for i in range(0, length):
wavedata = wavefile.readframes(1)
data = struct.unpack("<h", wavedata)
对于如下定义的 WAVE:
Input File : 'audio.wav'
Channels : 1
Sample Rate : 48000
Precision : 16-bit
Duration : 00:09:35.71 = 27634080 samples ~ 43178.2 CDDA sectors
File Size : 55.3M
Bit Rate : 768k
Sample Encoding: 16-bit Signed Integer PCM
加载完整音频平均需要 27.7 秒。 wave
模块的另一面是开箱即用,可在任何系统上运行。
方便的一个——音频文件
一个更方便快捷的解决方案是,例如audiofile。根据项目描述,它的重点是阅读速度。
import audiofile as af
signal, sampling_rate = af.read(audio.wav)
这给了我平均 33 毫秒的时间来阅读提到的文件。
最快的 - numpy
如果我们决定跳过 header(如 OP 所要求的那样)并完全追求速度,numpy
是一个不错的选择:
import numpy as np
byte_length = np.fromfile(filename, dtype=np.int32, count=1, offset=40)[0]
data = np.fromfile(filename, dtype=np.int16, count=byte_length // np.dtype(np.int16).itemsize, offset=44)
header 结构(告诉我们要使用什么 offset
)定义为 here。
该代码的执行时间约为 6 毫秒,比 audioread
少 5 倍。自然是有代价的/前提条件:我们需要提前知道数据类型是什么。
修改音频
一旦你在 numpy
数组中有了音频,你就可以随意修改它,你也可以决定流式传输文件而不是一次读取所有内容。但请注意:由于声音是波浪,在典型情况下,在任意时间简单地注入新数据 t
将导致音频失真(除非它是静音)。
至于写回流,“修改容器”在 Python 中会非常慢。这就是为什么您应该使用数组或切换到更合适的语言(例如 C)的原因。
如果我们使用数组,我们应该注意 numpy
对 WAVE 格式一无所知,因此我们必须自己定义 header 并写入单独的字节。完全可行的练习,但笨重。幸运的是,scipy 提供了一个方便的函数,它具有 numpy
速度的优势(它在下面使用 numpy
),同时使代码更具可读性:
from scipy.io.wavfile import write
fs = np.fromfile('audio.wav', dtype=np.int32, count=1, offset=24)[0] # we need sample rate
with open('audio_out.wav', 'a') as fout:
new_data = data.append(np.zeros(2 * fs)) # append 2 seconds of zeros
write(fout, fs, new_data)
它可以在一个循环中完成,您可以在其中使用 numpy / scipy 读取一个块,修改数组 (data
) 并写入文件(使用 a
for追加)。
学习如何修改不同类型的音频文件,.wav, .mp3 ,等等,使用 Python3 使用 wave
模块。具体是.wav文件格式,在这方面针对这个问题。目前,我知道音频格式有 ISO 标准,非常感谢有关此主题的关于 .wav 文件格式的音频标准的任何参考以及旁注。
但就我的问题而言,只需忽略 RIFF、FMT headers,在 [=28= .wav 文件使用 Python3 wave
模块导入。
有没有更高效的方式跳过RIFFheaders,其他容器,直接进入data容器修改其内容?
这个粗略的例子只是将 two-channel 音频 .wav 文件转换为 single-channel 音频 .wav 文件,同时将所有值修改为 (0, 0).
import wave
import struct
# Open Files
inf = wave.open(r"piano2.wav", 'rb')
outf = wave.open(r"output.wav", 'wb')
# Input Parameters
ip = list(inf.getparams())
print('Input Parameters:', ip)
# Example Output: Input Parameters: [2, 2, 48000, 302712, 'NONE', 'not compressed']
# Output Parameters
op = ip[:]
op[0] = 1
outf.setparams(op)
number_of_channels, sample_width, frame_rate, number_of_frames, comp_type, comp_name = ip
format = '<{}h'.format(number_of_channels)
print('# Channels:', format)
# Read >> Second
for index in range(number_of_frames):
frame = inf.readframes(1)
data = struct.unpack(format, frame)
# Here, I change data to (0, 0), testing purposes
print('Before Audio Data:', data)
print('After Modifying Audio Data', (0, 0))
# Change Audio Data
data = (0, 0)
value = data[0]
value = (value * 2) // 3
outf.writeframes(struct.pack('<h', value))
# Close In File
inf.close()
# Close Out File
outf.close()
如果只是修改.wav文件的数据段,是否有更好的做法或参考material?
- 假设您想在特定时间戳中逐字添加声音,这对我的问题来说是更合适的结果。
性能比较
让我们来看看读取 WAVE 文件的前 3 种方法。
最慢的一波模块
正如您可能已经注意到的那样,wave
模块可能非常慢。考虑这段代码:
import wave
import struct
wavefile = wave.open('your.wav', 'r') # check e.g. freesound.org for samples
length = wavefile.getnframes()
for i in range(0, length):
wavedata = wavefile.readframes(1)
data = struct.unpack("<h", wavedata)
对于如下定义的 WAVE:
Input File : 'audio.wav'
Channels : 1
Sample Rate : 48000
Precision : 16-bit
Duration : 00:09:35.71 = 27634080 samples ~ 43178.2 CDDA sectors
File Size : 55.3M
Bit Rate : 768k
Sample Encoding: 16-bit Signed Integer PCM
加载完整音频平均需要 27.7 秒。 wave
模块的另一面是开箱即用,可在任何系统上运行。
方便的一个——音频文件
一个更方便快捷的解决方案是,例如audiofile。根据项目描述,它的重点是阅读速度。
import audiofile as af
signal, sampling_rate = af.read(audio.wav)
这给了我平均 33 毫秒的时间来阅读提到的文件。
最快的 - numpy
如果我们决定跳过 header(如 OP 所要求的那样)并完全追求速度,numpy
是一个不错的选择:
import numpy as np
byte_length = np.fromfile(filename, dtype=np.int32, count=1, offset=40)[0]
data = np.fromfile(filename, dtype=np.int16, count=byte_length // np.dtype(np.int16).itemsize, offset=44)
header 结构(告诉我们要使用什么 offset
)定义为 here。
该代码的执行时间约为 6 毫秒,比 audioread
少 5 倍。自然是有代价的/前提条件:我们需要提前知道数据类型是什么。
修改音频
一旦你在 numpy
数组中有了音频,你就可以随意修改它,你也可以决定流式传输文件而不是一次读取所有内容。但请注意:由于声音是波浪,在典型情况下,在任意时间简单地注入新数据 t
将导致音频失真(除非它是静音)。
至于写回流,“修改容器”在 Python 中会非常慢。这就是为什么您应该使用数组或切换到更合适的语言(例如 C)的原因。
如果我们使用数组,我们应该注意 numpy
对 WAVE 格式一无所知,因此我们必须自己定义 header 并写入单独的字节。完全可行的练习,但笨重。幸运的是,scipy 提供了一个方便的函数,它具有 numpy
速度的优势(它在下面使用 numpy
),同时使代码更具可读性:
from scipy.io.wavfile import write
fs = np.fromfile('audio.wav', dtype=np.int32, count=1, offset=24)[0] # we need sample rate
with open('audio_out.wav', 'a') as fout:
new_data = data.append(np.zeros(2 * fs)) # append 2 seconds of zeros
write(fout, fs, new_data)
它可以在一个循环中完成,您可以在其中使用 numpy / scipy 读取一个块,修改数组 (data
) 并写入文件(使用 a
for追加)。