简体   繁体   中英

Changing a wav file's volume using Python

I have tried using the Pydub library; however, it only allows the reduction or increase of a certain amount of decibels. How would I proceed if I wanted, for example, to reduce the volume of the wav by a certain percent?

You could use the mul function from the built-in audioop module . This is what pydub uses internally , after converting the decibel value to a multiplication factor.

This is simple enough to just do with just the tools in the stdlib.

First, you use wave to open the input file and create an output file:

pathout = os.path.splitext(path)[0] + '-quiet.wav' 
with wave.open(path, 'rb') as fin, wave.open(pathout, 'wb') as fout:

Now, you have to copy over all the wave params, and hold onto the sample width for later:

fout.setparams(fin.getparams())
sampwidth = fin.getsampwidth()

Then you loop over frames until done:

while True:
    frames = bytearray(fin.readframes(1024))
    if not frames:
        break

You can use audioop to process this data:

frames = audioop.mul(frames, sampwidth, factor)

… but this will only work for 16-bit little-endian signed LPCM wave files (the most common kind, but not the only kind). You could solve that with other functions—most importantly, lin2lin to handle 8-bit unsigned LPCM (the second most common kind). But it's worth understanding how to do it manually:

for i in range(0, len(frames), sampwidth):
    if sampwidth == 1:
        # 8-bit unsigned
        frames[i] = int(round((sample[0] - 128) * factor + 128)
    else:
        # 16-, 24-, or 32-bit signed
        sample = int.from_bytes(frames[i:i+sampwidth], 'little', signed=True)
        quiet = round(sample * factor)
        frames[i:i+sampwidth] = int(quiet).to_bytes(sampwidth, 'little', signed=True)

audioop.mul only handles the else part—but it does more than I've done here. In particular, it has to handle cases with factors over 1—a naive multiply would clip, which will just add weird distortion without adding the desired max energy. (It's worth reading the pure Python implementation from PyPy if you want to learn the basics of this stuff.)

If you also want to handle float32 files, you need to look at the format, because they have the same sampwidth as int32, and you'll probably want the struct module or the array module to pack and unpack them. If you want to handle even less common formats, like a-law and µ-law, you'll need to read a more detailed format spec . Notice that audioop has tools for handling most of them, like ulaw2lin to convert µ-law to LPCM so you can process it and convert it back—but again, it might be worth learning how to do it manually. And for some of them, like CoolEdit float24/32, you pretty much have to do it manually.

Anyway, once you've got the quieted frames, you just write them out:

fout.writeframes(frames)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM