Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change the volume of a wav file in python

I have a 2 seconds 16bit single channel 8khz wav file and I need to change its volume.

It should be quite straightforward, because changing the volume is the same as changing the amplitude of the signal, and I just need to attenuate it, that is to multiply it for a number between 0 and 1. But it doesn't work: the new sound is lower but VERY full of noise. What am I doing wrong?

Here is my code:

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

Thank you guys!

like image 695
Ricard Bou Avatar asked Nov 11 '12 08:11

Ricard Bou


4 Answers

I wrote a library to simplify this type of thing

You can do that like so:

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")
like image 135
Jiaaro Avatar answered Sep 24 '22 18:09

Jiaaro


As you can see in the comments of the question, there are several solutions, some more efficient.

The problem was immediately detected by Jan Dvorak ("the * 5 part is clipping and overflowing") and the straightforward solution was:

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

In this case, this solution was perfect for me, just good enough.

Thank you all folks!

like image 35
Ricard Bou Avatar answered Sep 24 '22 18:09

Ricard Bou


This can be done with the audioop module in Python's standard library. This way, no dependencies like pydub or numpy are needed.

import wave, audioop

factor = 0.5

with wave.open('input.wav', 'rb') as wav:
    p = wav.getparams()
    with wave.open('output.wav', 'wb') as audio:
        audio.setparams(p)
        frames = wav.readframes(p.nframes)
        audio.writeframesraw( audioop.mul(frames, p.sampwidth, factor))
like image 28
dnknth Avatar answered Sep 21 '22 18:09

dnknth


The code which makes sound louder plus filter low and high frequencies

from pydub import AudioSegment

audio_file = "first.mp3"

song = AudioSegment.from_mp3(audio_file)

new = song.low_pass_filter(1000)

new1 = new.high_pass_filter(1000)

# increae volume by 6 dB
song_6_db_quieter = new1 + 6

# save the output
song_6_db_quieter.export("C://Users//User//Desktop//second.mp3", "mp3")
like image 22
Mindaugas Vaitkus Avatar answered Sep 21 '22 18:09

Mindaugas Vaitkus