[英]how to get wav samples from a wav file?
我想知道如何從.wav文件中獲取樣本,以便執行兩個.wav文件的窗口連接。
任何人都可以告訴我該怎么做?
標准庫的波形模塊是關鍵:當然,在代碼頂部import wave
之后, wave.open('the.wav', 'r')
返回一個“wave read”對象,您可以從中讀取幀使用.readframes
方法,該方法返回一個字節字符串,這些字節是波形文件具有的任何格式的樣本(您可以確定與使用.getnchannels
方法將幀分解為樣本的兩個參數相關的通道數和.getsampwidth
表示每個樣本的字節數)。
將字符串轉換為數值序列的最佳方法是使用array
模塊,並使用(分別) 'B'
, 'H'
, 'L'
的類型,每個樣本使用1,2,4個字節(on一個32位的Python構建;您可以使用數組對象的itemsize
值來仔細檢查這個)。 如果你有不同的array
樣本寬度可以提供給你,你需要切片字節字符串(適當地填充每個小片的值為0的字節)並使用結構模塊代替(但是這樣更笨拙和更慢,所以請使用array
代替如果你可以的話)。
您可以使用wave
模塊。 首先,您應該閱讀元數據,例如樣本大小或通道數。 使用readframes()
方法,您可以讀取樣本,但只能作為字節字符串。 根據樣本格式,您必須使用struct.unpack()
將它們轉換為樣本。
或者,如果您希望將樣本作為浮點數組,則可以使用SciPy的io.wavfile
模塊。
這是一個從波形文件中讀取樣本的功能(使用單聲道和立體聲測試):
def read_samples(wave_file, nb_frames):
frame_data = wave_file.readframes(nb_frames)
if frame_data:
sample_width = wave_file.getsampwidth()
nb_samples = len(frame_data) // sample_width
format = {1:"%db", 2:"<%dh", 4:"<%dl"}[sample_width] % nb_samples
return struct.unpack(format, frame_data)
else:
return ()
這里是完整的腳本,可以窗口混合或連接多個.wav
文件。 所有輸入文件都需要具有相同的參數(通道數和樣本寬度)。
import argparse
import itertools
import struct
import sys
import wave
def _struct_format(sample_width, nb_samples):
return {1:"%db", 2:"<%dh", 4:"<%dl"}[sample_width] % nb_samples
def _mix_samples(samples):
return sum(samples)//len(samples)
def read_samples(wave_file, nb_frames):
frame_data = wave_file.readframes(nb_frames)
if frame_data:
sample_width = wave_file.getsampwidth()
nb_samples = len(frame_data) // sample_width
format = _struct_format(sample_width, nb_samples)
return struct.unpack(format, frame_data)
else:
return ()
def write_samples(wave_file, samples, sample_width):
format = _struct_format(sample_width, len(samples))
frame_data = struct.pack(format, *samples)
wave_file.writeframes(frame_data)
def compatible_input_wave_files(input_wave_files):
nchannels, sampwidth, framerate, nframes, comptype, compname = input_wave_files[0].getparams()
for input_wave_file in input_wave_files[1:]:
nc,sw,fr,nf,ct,cn = input_wave_file.getparams()
if (nc,sw,fr,ct,cn) != (nchannels, sampwidth, framerate, comptype, compname):
return False
return True
def mix_wave_files(output_wave_file, input_wave_files, buffer_size):
output_wave_file.setparams(input_wave_files[0].getparams())
sampwidth = input_wave_files[0].getsampwidth()
max_nb_frames = max([input_wave_file.getnframes() for input_wave_file in input_wave_files])
for frame_window in xrange(max_nb_frames // buffer_size + 1):
all_samples = [read_samples(wave_file, buffer_size) for wave_file in input_wave_files]
mixed_samples = [_mix_samples(samples) for samples in itertools.izip_longest(*all_samples, fillvalue=0)]
write_samples(output_wave_file, mixed_samples, sampwidth)
def concatenate_wave_files(output_wave_file, input_wave_files, buffer_size):
output_wave_file.setparams(input_wave_files[0].getparams())
sampwidth = input_wave_files[0].getsampwidth()
for input_wave_file in input_wave_files:
nb_frames = input_wave_file.getnframes()
for frame_window in xrange(nb_frames // buffer_size + 1):
samples = read_samples(input_wave_file, buffer_size)
if samples:
write_samples(output_wave_file, samples, sampwidth)
def argument_parser():
parser = argparse.ArgumentParser(description='Mix or concatenate multiple .wav files')
parser.add_argument('command', choices = ("mix", "concat"), help='command')
parser.add_argument('output_file', help='ouput .wav file')
parser.add_argument('input_files', metavar="input_file", help='input .wav files', nargs="+")
parser.add_argument('--buffer_size', type=int, help='nb of frames to read per iteration', default=1000)
return parser
if __name__ == '__main__':
args = argument_parser().parse_args()
input_wave_files = [wave.open(name,"rb") for name in args.input_files]
if not compatible_input_wave_files(input_wave_files):
print "ERROR: mixed wave files must have the same params."
sys.exit(2)
output_wave_file = wave.open(args.output_file, "wb")
if args.command == "mix":
mix_wave_files(output_wave_file, input_wave_files, args.buffer_size)
elif args.command == "concat":
concatenate_wave_files(output_wave_file, input_wave_files, args.buffer_size)
output_wave_file.close()
for input_wave_file in input_wave_files:
input_wave_file.close()
在讀取樣本后(例如,使用波形模塊, 此處有更多詳細信息),您可能希望將值縮放在-1和1之間(這是音頻信號的慣例)。
在這種情況下,您可以添加:
# scale to -1.0 -- 1.0
max_nb_bit = float(2**(nb_bits-1))
samples = signal_int / (max_nb_bit + 1.0)
nb_bits
是位深度, signal_int
是整數值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.