2010-06-17 3 views

ответ

12

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 если сможешь).

+0

, когда я пытаюсь .getsamplewidth, он дал мне значение 2, что означает, что 2 байта. , когда я пытаюсь .readframes (1), должен вернуться 1, то он вернулся для меня, например, «/ x03/x16» , который, я думаю, составляет 2 байта, значит, это означает, что 1 кадр имеет только 1 образец. Что такое использование getnchannels ?? Я хочу выборочно отбирать образцы из каждого кадра и представлять их в intergers, как я могу? – kaki

+1

@kaki, в каждом кадре есть первый образец от каждого канала, затем второй образец от каждого канала, затем и так далее. Поэтому, если ваш звук не моно, т. Е. Всего один канал, вам нужно решить, что делать с каналами (пропустите все, кроме одного, усредните их, что угодно). Скажем, что это 1 канал (моно), самый простой, тогда 'x = array.array ('h', w.getframes (1))' дает вам в 'x' массив со всеми образцами первого кадра (следующий, если в цикле) как целые числа, как вы говорите, вы хотите ('h', а не' H': они подписаны). Если стерео, 2 канала, даже индексы 'x' имеют, например, образцы левого канала. Мало-endian btw. –

+0

BTW, формат docs на https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ не использует концепцию «фреймы», а скорее «куски» и «субханки», но, в конце концов, это к тому же, конечно же ;-). –

2

Вы можете использовать модуль wave. Сначала вы должны прочитать метаданные, такие как размер выборки или количество каналов. Используя метод readframes(), вы можете читать образцы, но только как байтовые строки. На основе формата образца вам необходимо преобразовать их в образцы с использованием struct.unpack().

Альтернативно, если вы хотите, чтобы образцы были массивом чисел с плавающей запятой, вы можете использовать модуль io.wavfile SciPy.

+0

Может ли рассказать мне, как получить образец в виде массива чисел точек floathf, не используя scipy – kaki

2

Вот функция для чтения выборок из файла волны (протестировано с моно & стерео):

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() 
0

После прочтения образцов (например, с помощью модуля волнового, более подробно 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 эти значения целых чисел.

Смежные вопросы