Play multiple sounds at the same time in python

12,773

Solution 1

Here is a simpler solution using pydub.

Using overlay function of AudioSegment module, you can very easily superimpose multiple audio on to each other.

Here is a working code to combine three audio files. Using same concept you can combine multiple audio onto each other.

More on overlay function here

pydub supports multiple audio formats as well.

from pydub import AudioSegment
from pydub.playback import play

audio1 = AudioSegment.from_file("chunk1.wav") #your first audio file
audio2 = AudioSegment.from_file("chunk2.wav") #your second audio file
audio3 = AudioSegment.from_file("chunk3.wav") #your third audio file

mixed = audio1.overlay(audio2)          #combine , superimpose audio files
mixed1  = mixed.overlay(audio3)          #Further combine , superimpose audio files
#If you need to save mixed file
mixed1.export("mixed.wav", format='wav') #export mixed  audio file
play(mixed1)                             #play mixed audio file

Here are updates as per our discussions.
First we create 44KHz signal and save to sound.wav
Next Read wave file and save signal to text file
Then create three variations of input signal to test overlay.
Original signal has dtype int16
Then we create three audio segments then mix/overlay as above. wav signal data is stored in test.txt

Working Modified Code

import numpy as np
from scipy.io.wavfile import read
from pydub import AudioSegment
from pydub.playback import play
import wave, struct, math


#Create 44KHz signal and save to 'sound.wav'
sampleRate = 44100.0 # hertz
duration = 1.0       # seconds
frequency = 440.0    # hertz

wavef = wave.open('sound.wav','w')
wavef.setnchannels(1) # mono
wavef.setsampwidth(2) 
wavef.setframerate(sampleRate)

for i in range(int(duration * sampleRate)):
    value = int(32767.0*math.cos(frequency*math.pi*float(i)/float(sampleRate)))
    data = struct.pack('<h', value)
    wavef.writeframesraw( data )

wavef.writeframes('')
wavef.close()

#Read wave file and save signal to text file
rate, signal = read("sound.wav")

np.savetxt('test.txt', signal, delimiter=',')   # X is an array


#load wav data from text file
wavedata1 = np.loadtxt("test.txt", comments="#", delimiter=",", unpack=False, dtype=np.int16)

#Create variation of signal
wavedata2 = np.loadtxt("test.txt", comments="#", delimiter=",", unpack=False, dtype=np.int32)

#Create variation of signal
wavedata3 = np.loadtxt("test.txt", comments="#", delimiter=",", unpack=False, dtype=np.float16)

#create first audio segment
audio_segment1 = AudioSegment( 
    wavedata1.tobytes(), 
    frame_rate=rate,
    sample_width=2, 
    channels=1
)

#create second audio segment
audio_segment2 = AudioSegment( 
    wavedata2.tobytes(), 
    frame_rate=rate,
    sample_width=2, 
    channels=1
)

#create third audio segment
audio_segment3 = AudioSegment( 
    wavedata3.tobytes(), 
    frame_rate=rate,
    sample_width=2, 
    channels=1
)

# Play audio (requires ffplay, or pyaudio):
play(audio_segment1)
play(audio_segment2)
play(audio_segment3)

#Mix three audio segments
mixed1 = audio_segment1.overlay(audio_segment2)          #combine , superimpose audio files
mixed2  = mixed1.overlay(audio_segment3)          #Further combine , superimpose audio files
#If you need to save mixed file
mixed2.export("mixed.wav", format='wav') #export mixed  audio file
play(mixed2)                             #play mixed audio file

Solution 2

I suggest using Pyaudio to do this.

import pyaudio 
import wave
sound1 = wave.open("/path/to/sound1", 'rb')
sound2 = wave.open("/path/to/sound2", 'rb')

def callback(in_data, frame_count, time_info, status):
    data1 = sound1.readframes(frame_count)
    data2 = sound2.readframes(frame_count)
    decodeddata1 = numpy.fromstring(data1, numpy.int16)
    decodeddata2 = numpy.fromstring(data2, numpy.int16)
    newdata = (decodeddata1 * 0.5 + decodeddata2* 0.5).astype(numpy.int16)
    return (newdata.tostring(), pyaudio.paContinue)

Solution 3

Using multiple threads will solve your problem :

import threading
from audiolazy import AudioIO

sound = Somelist
with AudioIO(True) as player:
  t = threading.Thread(target=player.play, args=(sound,), kwargs={'rate':44100})
  t.start()
Share:
12,773
Admin
Author by

Admin

Updated on September 15, 2022

Comments

  • Admin
    Admin over 1 year

    I have been looking into a way to play sounds from a list of samples, and I found some modules that can do this.

    I am using AudioLazy module to play the sound using the following script:

    from audiolazy import AudioIO
    
    sound = Somelist
    with AudioIO(True) as player:
      player.play(sound, rate=44100)
    

    The problem with this code is that it stop the whole application till the sound stop playing and I can't play multiple sound at the same time.

    My program is interactive so what I want is to be able to play multiple sound at the same time,So for instance I can run this script which will play a 5 second sound then at the second 2 I can play a 5 second sound again.

    And I don't want the whole program to stop till the sound finish playing.

  • Admin
    Admin over 7 years
    It still not working, Putting in mind that this script will be converted into a function,I mean the whole script will be inside a function.This is how the program I am programming for works. will this have an impact?
  • Loïc
    Loïc over 7 years
    No it should be fine. How so it's not working? Do you have any error?
  • Admin
    Admin over 7 years
    The whole programe freeze while the sound is playing,and if I tried to play 2 sounds at once, python just play the first sound wait till it finish then play the next sound.
  • Admin
    Admin over 7 years
    My script read samples (floats) and not wave files,can his be done using pydud?
  • Anil_M
    Anil_M over 7 years
    What kind of samples? can you post a sizable example? It may be possible to generate audio-segment from samples, frame-rate and sample_width. See audiosegment.py for details
  • Admin
    Admin over 7 years
    A sample like [0,0.1,0.2,0.3,0.4,0.5,0.4,0.3,0.2,0.1,0] A sine wave for instance.
  • Anil_M
    Anil_M over 7 years
    See modifications above. I saved wav file to text and created audio_segment from there. This mimics your sample. Let me know if this helps