Stereo to mono wave interpolation in python

假如想象 提交于 2020-12-07 04:50:12

问题


I'm trying to open a stereo stream and convert it to mono, using the wave module in python. So far I was able to write a single (left or right) channel from a 16bit stereo little endian file:

LEFT, RIGHT = 0, 1
def mono_single(cont, chan=LEFT):
    a = iter(cont)
    mono_cont = ''
    if chan:
        a.next(); a.next()
    while True:
        try:                          
            mono_cont += a.next() + a.next()
            a.next(); a.next()
        except StopIteration:
            return mono_cont

stereo = wave.open('stereofile.wav', 'rb')
mono = wave.open('monofile.wav', 'wb')
mono.setparams(stereo.getparams())
mono.setnchannels(1)
mono.writeframes(mono_single(stereo.readframes(stereo.getnframes())))
mono.close()

This works as expected. The problem comes when I try to downmix the two stereo channels to a single mono channel. I thought that a simple average between left and right would have been enough, and this is what I tried so far:

def mono_mix(cont):
    a = iter(cont)
    mono_cont = ''
    while True:
        try:
            left = ord(a.next()) + (ord(a.next()) << 8)
            right = ord(a.next()) + (ord(a.next()) << 8)
            value = (left + right) / 2
            mono_cont += chr(value & 255) + chr(value >> 8)
        except StopIteration:
            return mono_cont

stereo = wave.open('stereofile.wav', 'rb')
mono = wave.open('monofile.wav', 'wb')
mono.setparams(stereo.getparams())
mono.setnchannels(1)
mono.writeframes(mono_mix(stereo.readframes(stereo.getnframes())))
mono.close()

What I get from this is a "crackled" version of the source. I tried different combinations (I might have misunderstood the whole endianness thing), but with no luck so far.


回答1:


Are you open to using external libraries?
if yes, you can do this easily with pydub very few lines as follows,

from pydub import AudioSegment
mysound = AudioSegment.from_wav("/input_path/infile.wav")
mysound = mysound.set_channels(1)
mysound.export("/output_path/outfile.wav", format="wav")



回答2:


Turns out like I didn't know about the audioop built-in module (thanks to Anil_M's answer. Also, I was wrong on both converting the stereo format and writing (I should have used struct).

This makes everything absolutely easier:

stereo = wave.open('stereofile.wav', 'rb')
mono = wave.open('monofile.wav', 'wb')
mono.setparams(stereo.getparams())
mono.setnchannels(1)
mono.writeframes(audioop.tomono(stereo.readframes(float('inf')), stereo.getsampwidth(), 1, 1))
mono.close()

Then you can select a single channel by modifying the latest 2 parameters (1, 0 for left, 0, 1 for right) or even using 1.414 for equal power instead of equal amplitude



来源:https://stackoverflow.com/questions/43056088/stereo-to-mono-wave-interpolation-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!