问题
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