Onion
Onion

Reputation: 177

Inserting a WAV at a certain point in an audio file using python

My problem is the following: I have a 2-minute long WAV file, and my aim is to insert another WAV file (7 seconds long), at a certain point in the first WAV file (say, 0:48), essentially combining the two WAVs, using python. Unfortunately I haven't been able to figure out how to do that, and was wondering if there was some obvious solution that I was missing, or if it is even feasible to do with python. Is there perhaps a library available that might provide a solution? Thanks to all in advance.

UPDATE based on a comment by the OP:

I should have clarified that I wanted the inserted wav to "overlap" the original wav so that both would play, my apologies. Is there any way of achieving such an effect?

Upvotes: 2

Views: 2247

Answers (5)

Oleg Kokorin
Oleg Kokorin

Reputation: 2672

following is the way to merge 2 audio sample buffers

assuming both buffers / files are the same format / same number of channels / same sampling frequency, all 3 data are the bin string sample buffers of the same length (!important), sampleFormat is a number of bytes per sample, ex: for 16bit sampling it would be = 2 :

import audioop

merged_data = audioop.add(firstWave_data, secondWave_data, sampleFormat)

otherwise prepare to perform following buffers preparation first:

  1. making mono/stereo transformation
  2. making format transformation
  3. resampling tranformation

Upvotes: 0

Jiaaro
Jiaaro

Reputation: 76918

use the pydub package (full disclosure - I wrote it)

from pydub import AudioSegment

sound1 = AudioSegment.from_wav('your_wave.mp3')
the_wave = AudioSegment.from_wav('the_7sec_wave.wav')

sound_with_wave = sound1.overlay(the_wave, position=48*1000)

sound_with_wave.export('overlaid.wav', format='wav')

Upvotes: 1

tzot
tzot

Reputation: 95931

Loosely based on the code by Justin, here is some other code that probably does what you want:

import wave, audioop

def merge_wav_at_offset(wav_in1, wav_in2, offset, wav_out):
    """Merge two wave files, with the second wave starting at offset seconds
    The two input wave files should have the same frame rate, channels, depth
    Also, offset should be non-negative and can be floating point."""
    wf1= wave.open(wav_in1, 'rb')
    wf2= wave.open(wav_in2, 'rb')
    wfo= wave.open(wav_out, 'wb')

    wfout.setparams(wf1.getparams())

    frame_rate = wf1.getframerate()
    sample_width= wf1.getsampwidth()
    if offset < 0:
        offset= 0
    prologue_frames= int(frame_rate*offset)
    merge_frames= wf2.getnframes()

    # prologue
    frames_to_read= prologue_frames
    while frames_to_read > 0:
        chunk_size= min(frame_rate, frames_to_read)
        wfo.writeframes(wf1.readframes(chunk_size))
        frames_to_read-= chunk_size

    # merging
    frames_to_read= merge_frames
    while frames_to_read > 0:
        chunk_size= min(frame_rate, frames_to_read)
        frames2= wf2.readframes(chunk_size)

        if frames2:
            frames1= wf1.readframes(chunk_size)
            if len(frames1) != len(frames2): # sanity check
                # obviously you should cater for this case too
                raise NotImplementedError, "offset+duration(wf2) > duration(wf1)"
            merged_frames= audioop.add(frames1, frames2, sample_width)
            wfo.writeframes(merged_frames)
        else: # early end of wf2 data; improbable but possible
            break

        frames_to_read-= chunk_size

    # epilogue
    while True:
        frames= wf1.readframes(frame_rate)
        if not frames: break
        wfo.writeframes(frames)

    for wave_file in wf1, wf2, wfo:
        wave_file.close()

I just wrote the code without testing, so it's possible that I have a bug (even syntax errors); however, my experience with Python is that often the code runs as-is;-) If you need anything more, let me know.

Upvotes: 1

Justin Peel
Justin Peel

Reputation: 47082

Here's some code to get you in the right direction:

wf = wave.open('in1.wav','rb')
wf2 = wave.open('in2.wav','rb')
wfout = wave.open('out.wav','wb')

wfout.setparams(wf.getparams())

sr = wf.getframerate()
for x in xrange(48):
    wfout.writeframes(wf.readframes(sr)
wfout.writeframes(wf2.readframes(sr))
for x in xrange(72):
    wfout.writeframes(wf.readframes(sr))

This should do what you've described in your question (adding a 1 second clip 48 seconds into a 2 minute song) as long as the waves are in the same format (same sampling rate, same number of channels, etc.). You can probably read/write bigger chunks than a second, but I did them as 1 second chunks to be safe.

Upvotes: 0

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798676

If they're PCM-encoded then you can use wave, otherwise use something like pygst.

Upvotes: 1

Related Questions