2

I'm coding in python and using the "wave" library. I've managed to save new wave files with this library, but not with two sound files overlapping - they will be played one after another when saved. if anyone could help with how to save a file where two tracks play at the same time at different volumes would be great. thanks.

Sh0z
  • 127
  • 1
  • 2
  • 7
  • Possible duplicate of [Mixing two audio files together with python](http://stackoverflow.com/questions/4039158/mixing-two-audio-files-together-with-python) – litepresence Apr 01 '17 at 18:50

1 Answers1

2

You can use the pydub library (a light wrapper I wrote around the python wave module in the std lib) to do it pretty simply:

from pydub import AudioSegment

sound1 = AudioSegment.from_file("/path/to/my_sound.wav")
sound2 = AudioSegment.from_file("/path/to/another_sound.wav")

combined = sound1.overlay(sound2)

combined.export("/path/to/combined.wav", format='wav')

but if you really want to do it using wave:

this is very dependent of the format these are in. Here's an example of how to do it assuming 2 byte wide, little-endian samples:

import wave

w1 = wave.open("/path/to/wav/1")
w2 = wave.open("/path/to/wav/2")

#get samples formatted as a string.
samples1 = w1.readframes(w1.getnframes())
samples2 = w2.readframes(w2.getnframes())

#takes every 2 bytes and groups them together as 1 sample. ("123456" -> ["12", "34", "56"])
samples1 = [samples1[i:i+2] for i in xrange(0, len(samples1), 2)]
samples2 = [samples2[i:i+2] for i in xrange(0, len(samples2), 2)]

#convert samples from strings to ints
def bin_to_int(bin):
    as_int = 0
    for char in bin[::-1]: #iterate over each char in reverse (because little-endian)
        #get the integer value of char and assign to the lowest byte of as_int, shifting the rest up
        as_int <<= 8
        as_int += ord(char) 
    return as_int

samples1 = [bin_to_int(s) for s in samples1] #['\x04\x08'] -> [0x0804]
samples2 = [bin_to_int(s) for s in samples2]

#average the samples:
samples_avg = [(s1+s2)/2 for (s1, s2) in zip(samples1, samples2)]

And now all that's left to do is convert samples_avg back to a binary string and write that to a file using wave.writeframes. That's just the inverse of what we just did, so it shouldn't be too hard to figure out. For your int_to_bin function, you'll probably what to make use of the function chr(code), which returns the character with the character code of code (opposite of ord)

Liam
  • 6,009
  • 4
  • 39
  • 53
  • thanks for all the help- pydub is what i need. but when i tried to import AudioSegment in python it doesn't recognize it. (i pip installed pydub and tried doing the same for AudioSegment). How can i fix that problem? – Sh0z Apr 02 '17 at 14:16
  • wanted to add that i tried searching online and also found nothing – Sh0z Apr 02 '17 at 14:25