Я хочу знать, как получить образцы из .wav-файла, чтобы выполнить оконное соединение двух .wav-файлов.Как получить образцы wav из wav-файла?
Может ли кто-нибудь рассказать, как это сделать?
Я хочу знать, как получить образцы из .wav-файла, чтобы выполнить оконное соединение двух .wav-файлов.Как получить образцы wav из wav-файла?
Может ли кто-нибудь рассказать, как это сделать?
wave модуль стандартной библиотеки является ключом: после того, как, конечно, import wave
в верхней части кода, wave.open('the.wav', 'r')
возвращает «волна чтения» объект, из которого вы можете прочитать кадры с .readframes
метод, который возвращает строку байты, которые являются образцами ... в любом формате, который имеет волновой файл (вы можете определить два параметра, относящихся к разложению кадров в выборках с помощью метода .getnchannels
для количества каналов, и .getsampwidth
для количества байтов на выборку).
Лучший способ превратить строку байт в последовательность цифровых значений с array
модулем, а также тип (соответственно) 'B'
, 'H'
, 'L'
в течение 1, 2, 4 байта на образец (на 32 -битной сборки Python, вы можете использовать значение itemsize
вашего объекта массива, чтобы дважды проверить это). Если у вас есть различная ширина выборки, чем array
, вы можете отрезать строку байта (заполняя каждый маленький фрагмент соответствующим образом байтами 0) и вместо этого использовать модуль struct (но это неуклюже и медленнее, поэтому вместо этого используйте array
если сможешь).
Вы можете использовать модуль wave
. Сначала вы должны прочитать метаданные, такие как размер выборки или количество каналов. Используя метод readframes()
, вы можете читать образцы, но только как байтовые строки. На основе формата образца вам необходимо преобразовать их в образцы с использованием struct.unpack()
.
Альтернативно, если вы хотите, чтобы образцы были массивом чисел с плавающей запятой, вы можете использовать модуль io.wavfile
SciPy.
Может ли рассказать мне, как получить образец в виде массива чисел точек floathf, не используя scipy – kaki
Вот функция для чтения выборок из файла волны (протестировано с моно & стерео):
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()
А вот полный скрипт, который делает WINDOWED смешивание или конкатенации из нескольких .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()
После прочтения образцов (например, с помощью модуля волнового, более подробно here) вы можете иметь значения шкалы между -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
эти значения целых чисел.
, когда я пытаюсь .getsamplewidth, он дал мне значение 2, что означает, что 2 байта. , когда я пытаюсь .readframes (1), должен вернуться 1, то он вернулся для меня, например, «/ x03/x16» , который, я думаю, составляет 2 байта, значит, это означает, что 1 кадр имеет только 1 образец. Что такое использование getnchannels ?? Я хочу выборочно отбирать образцы из каждого кадра и представлять их в intergers, как я могу? – kaki
@kaki, в каждом кадре есть первый образец от каждого канала, затем второй образец от каждого канала, затем и так далее. Поэтому, если ваш звук не моно, т. Е. Всего один канал, вам нужно решить, что делать с каналами (пропустите все, кроме одного, усредните их, что угодно). Скажем, что это 1 канал (моно), самый простой, тогда 'x = array.array ('h', w.getframes (1))' дает вам в 'x' массив со всеми образцами первого кадра (следующий, если в цикле) как целые числа, как вы говорите, вы хотите ('h', а не' H': они подписаны). Если стерео, 2 канала, даже индексы 'x' имеют, например, образцы левого канала. Мало-endian btw. –
BTW, формат docs на https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ не использует концепцию «фреймы», а скорее «куски» и «субханки», но, в конце концов, это к тому же, конечно же ;-). –