Изменить объем файла WAV в Python

У меня есть 2-секундный 16-битный 8-канальный WAV-файл с одним каналом, и мне нужно изменить его громкость.

Это должно быть довольно просто, потому что изменение громкости - это то же самое, что изменение амплитуды сигнала, и мне просто нужно его ослабить, то есть умножить на число от 0 до 1. Но это не так.t работает: новый звук ниже, но ОЧЕНЬ полон шума. Что я делаю неправильно?

Вот мой код:

import wave, numpy, struct

# Open
w = wave.open("input.wav","rb")
p = w.getparams()
f = p[3] # number of frames
s = w.readframes(f)
w.close()

# Edit
s = numpy.fromstring(s, numpy.int16) * 5 / 10  # half amplitude
s = struct.pack('h'*len(s), *s)

# Save
w = wave.open("output.wav","wb")
w.setparams(p)
w.writeframes(s)
w.close()

Спасибо вам, ребята!

 John Dvorak11 нояб. 2012 г., 09:27
Почему вы используете* 5 / 10 вместо ?/ 2
 eryksun11 нояб. 2012 г., 12:17
Если оно's масштабируется поплавком, просто используяtostring даст неправильный результат. Но вместо этого вы могли бы сделать.s = (s * (desired/original)).astype(numpy.int16).tostring()
 Ricard Bou11 нояб. 2012 г., 09:34
Ян, потому что они должны быть vars: 5 - желаемый объем, а 10 - оригинальный объем.
 Ricard Bou11 нояб. 2012 г., 09:34
Ник, ДА !! Вы правы. Спасибо!
 John Dvorak11 нояб. 2012 г., 09:33
Вы читаете файл в правильном порядке байтов?WAV-файлы имеют порядок байтов. Использование другого порядка байтов уменьшит пополам сэмпл и добавит много шума.
 user481516234211 нояб. 2012 г., 09:40
Другое дело:* оператор вstruct.pack('h', *s) line преобразует весь массив NumPy в кортеж объектов int. Это потенциально очень неэффективновы должны использоватьs.tostring вместо этого это будет эффективно создавать строку непосредственно из содержимого массива.
 Ricard Bou11 нояб. 2012 г., 09:36
Спасибо, Ян, но stackoverflow позволяет мне подождать еще 7 часов, прежде чем я смогу опубликовать ответ ... :)
 John Dvorak11 нояб. 2012 г., 09:35
Вы должны опубликовать свой комментарий в качестве ответа и принять его, когда это возможно (+ 24 часа IIRC)
 Nick ODell11 нояб. 2012 г., 09:28
Если бы мне пришлось угадывать, яя бы сказал, что* 5 часть отсечения и переполнения.
 Ricard Bou11 нояб. 2012 г., 09:33
О, мой ... !! Извините за публикацию этого ... Ответ был слишком легок. Делая это: s = numpy.fromstring (s, numpy.int16) * 5/10 # половина амплитуды Сигнал насыщен, потому что я умножил целые числа перед их делением. Решение: s = numpy.fromstring (s, numpy.int16) / 10 * 5 # половинная амплитуда. Будьте осторожны, это НЕ работает, так как результат деления равен нулю: s = numpy.fromstring (s, numpy.int16) * (5 / 10) # половина амплитуды Я сохраняю это здесь на случай, если это поможет кому-то еще
 user481516234211 нояб. 2012 г., 09:37
@JanDvorak Так как вы нашли проблему, было бы справедливо, если бы вы опубликовали ответ, и ОП принял его. Полное решение, вероятно, будет включать умножение на.float(desired_volume) / float(orig_volume)
 John Dvorak11 нояб. 2012 г., 09:39
@ user4815162342 Жаль, что яЯ не владею питоном. Я не'даже не знаю, не питон лиТипы поплавка не используются для всего.

Ответы на вопрос(2)

библиотека, чтобы упростить этот тип вещи

Вы можете сделать это так:

from pydub import AudioSegment

song = AudioSegment.from_wav("never_gonna_give_you_up.wav")

# reduce volume by 10 dB
song_10_db_quieter = song - 10

# but let's make him *very* quiet
song = song - 36

# save the output
song.export("quieter.wav", "wav")
 msw05 дек. 2012 г., 23:59
Не могли бы вы вместо Мистера Астли на 36 дБ?
 Jiaaro06 дек. 2012 г., 00:10
@ MSW уверен, что это будетsong = song - 36
Решение Вопроса

есть несколько решений, некоторые более эффективные.

Проблема была сразу обнаружена Яном Двораком ("* 5 часть отсечения и переполнения ") и простым решением было:

s = numpy.fromstring(s, numpy.int16) / 10 * 5

В данном случае это решение было для меня идеальным, просто достаточно хорошим.

Спасибо всем, ребята!

Ваш ответ на вопрос