33

I am using python programming language,I want to join to wav file one at the end of other wav file? I have a Question in the forum which suggest how to merge two wav file i.e add the contents of one wav file at certain offset,but i want to join two wav file at the end of each other...

And also i had a prob playing the my own wav file,using winsound module..I was able to play the sound but using the time.sleep for certain time before playin any windows sound,disadvantage wit this is if i wanted to play a sound longer thn time.sleep(N),N sec also,the windows sound wil jst overlap after N sec play the winsound nd stop..

Can anyone help??please kindly suggest to how to solve these prob...

Thanks in advance

tom10
  • 67,082
  • 10
  • 127
  • 137
kaushik
  • 5,609
  • 4
  • 23
  • 17

8 Answers8

64

Python ships with the wave module that will do what you need. The example below works when the details of the files (mono or stereo, frame rates, etc) are the same:

import wave

infiles = ["sound_1.wav", "sound_2.wav"]
outfile = "sounds.wav"

data= []
for infile in infiles:
    w = wave.open(infile, 'rb')
    data.append( [w.getparams(), w.readframes(w.getnframes())] )
    w.close()
    
output = wave.open(outfile, 'wb')
output.setparams(data[0][0])
for i in range(len(data)):
    output.writeframes(data[i][1])
output.close()
miguelmorin
  • 5,025
  • 4
  • 29
  • 64
tom10
  • 67,082
  • 10
  • 127
  • 137
  • This method fails when the sampling rate of the wav files to concatenate is larger than 48kHz. – Bruce May 27 '22 at 01:44
  • 1
    I just tried joining two 96kHz 24bit wav files and this code worked fine. Note that this approach assumes that files have the same format, and a mismatch is the usual reason it fails. If there is a mismatch, installing a more advanced library (like pydub described in another answer here) will be necessary (or at least the easiest approach). – tom10 May 28 '22 at 01:57
49

I'm the maintainer of pydub, which is designed to make this sort of thing easy.

from pydub import AudioSegment

sound1 = AudioSegment.from_wav("/path/to/file1.wav")
sound2 = AudioSegment.from_wav("/path/to/file2.wav")

combined_sounds = sound1 + sound2
combined_sounds.export("/output/path.wav", format="wav")

note: pydub is a light wrapper around audioop. So behind the scenes, it's doing essentially what Tom10 mentioned

Jiaaro
  • 74,485
  • 42
  • 169
  • 190
7

Python 3 solution:
We can do this with the standard library as shown by tom10 and eggbert's answers.
Below is a shorter version:

  1. Only write the parameters for the first wave file. We can test the wav_out file length to see if we haven't yet written to it. If we haven't write the wave parameters once only.
  2. Then write frames to the wav_out as they are read from the wav_in.

    with wave.open(outfile, 'wb') as wav_out:
        for wav_path in infiles:
            with wave.open(wav_path, 'rb') as wav_in:
                if not wav_out.getnframes():
                    wav_out.setparams(wav_in.getparams())
                wav_out.writeframes(wav_in.readframes(wav_in.getnframes()))
    
spacether
  • 2,136
  • 1
  • 21
  • 28
5

Just to build on @tom10's answer:

from contextlib import closing

with closing(wave.open(outfile, 'wb')) as output:

    # find sample rate from first file
    with closing(wave.open(wav_files[0])) as w:
        output.setparams(w.getparams())

    # write each file to output
    for infile in wav_files:
        with closing(wave.open(infile)) as w:
            output.writeframes(w.readframes(w.getnframes()))

Instead of storing all the data then writing it at the end in one go, it writes it bit by bit. It also uses contextlib.close so you don't have to close files.

eggbert
  • 3,105
  • 5
  • 30
  • 39
  • In python3 it looks like we don't need the contextlib wrapper per: "The open() function may be used in a with statement. When the with block completes, the Wave_read.close() or Wave_write.close() method is called." https://docs.python.org/3/library/wave.html – spacether Mar 23 '18 at 00:59
4

I used pysox

The wave module and many others don't seem to support mu-law wavs.

pysox reqs that you install SoX and update your PATH to include the directory it's installed to.

import sox    
cbn=sox.Combiner()
sounds=[]
#PROCESS SOUND PATHS TO AN ARRAY
if len(sounds)>=2:
    print(sounds)
    cbn.build(sounds,'outputfilepath.ext','concatenate')
3

You could use audiolab:

import audiolab, scipy
a, fs, enc = audiolab.wavread('file1.wav')
b, fs, enc = audiolab.wavread('file2.wav')
c = scipy.vstack((a,b))
audiolab.wavwrite(c, 'file3.wav', fs, enc)
Steve Tjoa
  • 59,122
  • 18
  • 90
  • 101
  • do i need to install any package for using scipy...I am using a python2.6 can i get a compatible version for download if i have to..can u provide me the link please..i tried to frm scipy site itself bt faced sme prob..if ne there steps fot installation please suggest..Thank u for the answer.. Do u know how to play the sound,i mentioned my prob wit playin,any measure fr that?? – kaushik May 23 '10 at 05:35
  • Python 2.6 is fine, and the Numpy/Scipy website should also be fine. I might let others answer your questions and provide further suggestions. Although my answer does work, there are probably more elegant, direct solutions. – Steve Tjoa May 23 '10 at 05:50
  • I tried installation of audiolab from scikits which is about a size of 1.4 mb and was succesfully installed,but when running ur code it says import error: no module named audiolab..i didnt install the 44mb scipy package is that the prob,do i need to instal that also or the audioalab download itself is incorrect – kaushik May 23 '10 at 07:08
  • I installed Scipy too but stil says import error..I am using window downloaded both and installed later..stil there prob what mmay b d reason.. – kaushik May 23 '10 at 07:29
  • 1
    These days, I would use `librosa`. http://librosa.github.io/librosa/generated/librosa.core.load.html#librosa.core.load – Steve Tjoa May 03 '18 at 18:10
3

I would use librosa.load and librosa.write_wav. Check out the doc here

import librosa
import numpy as np
import librosa.display

example_audio = librosa.util.example_audio_file()
x, sr = librosa.load(example_audio, duration=5)
print('shape of x ==> ' + str(x.shape))
y, sr = librosa.load(example_audio, duration=5)
print('shape of y ==> ' + str(y.shape))
z = np.append(x,y)
print('shape of x+y = z ==> ' + str(z.shape))
librosa.output.write_wav('joined_file.wav', z, sr)

z_loaded, sr = librosa.load('joined_file.wav')
print('shape of z loaded ==> ' + str(z_loaded.shape))

Output:

shape of x ==> (110250,)

shape of y ==> (110250,)

shape of x+y = z ==> (220500,)

shape of z loaded ==> (220500,)

penduDev
  • 4,743
  • 35
  • 37
  • 1
    @Ryan updated the answer. You might be interested in more code samples here : https://github.com/gndps/vocal-training/blob/master/7_phrasedetection.ipynb not very easy to read doc though – penduDev Aug 06 '18 at 17:22
  • fyi that `librosa` comes with `numpy`, `scipy`, `scikit-learn`, which may be overkill for those who just want to combine WAV files – Tyler Dane Aug 09 '19 at 22:19
0

i use the SOX [1] library and then call it like

>>> import subprocess
>>> sound_output_path = /tmp
>>> sox_filenames = ['file.wav', 'file1.wav']
>>> subprocess.call(['sox'] + sox_filenames + ['%s/out.wav' % sound_output_path])

[1] http://sox.sourceforge.net/