Умножение массива выборок на коэффициент масштабирования дает неоднозначные результаты при чтении / записи WAV-файлов - PullRequest
0 голосов
/ 17 июня 2019

Мне нужно манипулировать некоторыми .wav файлами, и я использую модуль scipy.io.wavfile, чтобы помочь мне с этой задачей.

Я столкнулся с проблемой, когда попытался понять, как работают функции read и write.

У меня есть образец файла input_file.wav. Код, который я написал, который работал как ожидалось, был:

def scale(filename):
    fs, x = wavfile.read(filename)
    wavfile.write('test_output.wav', fs, x)
    return
scale('input_file.wav')

Входные и выходные файлы выглядели одинаково, когда я импортировал их в Audacity, и звучали одинаково на моих наушниках. Я столкнулся с проблемами при выполнении следующего кода.

def scale(filename):
    fs, x = wavfile.read(filename)
    x1 = x * 0.5
    wavfile.write('test_output1.wav', fs, x1)
    return
scale('input_file.wav')

Я ожидал, что выходной сигнал будет вдвое громче (так как я умножил значение каждого сэмпла на 0,5. Но когда я импортировал его в Audacity, файл был громким до точки серьезного искажения.

То же самое произошло, когда я умножил на 1.01, 1.0001, 0.1 и ряд других опробованных мной значений - громко увеличил громкость до уровня больших искажений.

Файл начал звучать идентично (и выглядеть одинаково при импорте в Audacity), когда я умножил массив семплов на значение 1/32767 или около того (то есть 1/(2^15-1)). Это странно, потому что значения в массиве примеров, возвращаемые функцией read(), определенно не идентичны.

Почему выходные файлы из операции записи звучат одинаково, когда значение масштабирования равно 1 или 1/32767, два совершенно разных числа?

Любая помощь будет оценена, спасибо.

РЕДАКТИРОВАТЬ: Если это помогает, вывод x.dtype (атрибут dtype массива выборки, возвращаемый read(), равен int16).

1 Ответ

1 голос
/ 17 июня 2019

Если x имеет dtype np.int16, то x1 имеет dtype np.float64. Похоже, что scipy.io.wavfile.write пытается записать 64-битные значения с плавающей запятой в файл, хотя в документации упоминаются только 32-битные форматы с плавающей запятой. Вы можете обойти эту проблему, преобразовав x1 в int16 или нормализовав значения в x1 в диапазон [-1, 1] (или [-0,5, 0,5], или в любой другой диапазон, который вы хотите в [-1, 1]). То есть вы можете использовать

wavfile.write('test_output1.wav', fs, np.round(x1).astype(x.dtype))  # If x has an integer dtype

или

wavfile.write('test_output1.wav', fs, (x1/2**15).astype(np.float32))
...