Question

I need to play 2 sounds simultaneously, with multiprocessing rather than threads, to see if it solves a problem where threads play the audio in sequence rather than in parallel. I am guessing it's due to the Global Interpreter Lock (GIL) in python.

I added a question 2 days ago, but my description is overcomplicated. This is the simple version:

The audio gets imported as numpy array. I take this array and play it using the scikits.audiolab module:

import scikits.audiolab as audiolab

# This is how I import my wav file. "frames" is the numpy array, "fs" = sampling 
# frequency, "encoder" = quantizing at 16 bits

frames, fs, encoder = audiolab.wavread('audio.wav')

# This is how I play my wav file. audiolab plays the frames array at a frequency of 
# 44100 Hz
audiolab.play(frames, fs=44100)

That's fine, but this is what I need help on: playing 2 files at the same time using multiprocessing.

frames1, fs1, encoder1 = audiolab.wavread('audio1.wav')
frames2, fs2, encoder2 = audiolab.wavread('audio2.wav')

audiolab.play(frames1, fs=44100)
audiolab.play(frames2, fs=44100)
Was it helpful?

Solution

If you want to have any control over the relative timing of the two sounds (for example, they should start simultaneously), using multiple processes is probably not a good solution. You should be mixing the signals within your application and writing out a single audio stream.

Since you are using audiolab, you already have the data in numpy arrays. This gives you all the flexibility you need to mix audio:

frames1, fs1, encoder1 = audiolab.wavread('audio1.wav')
frames2, fs2, encoder2 = audiolab.wavread('audio2.wav')
mixed = frames1 + frames2

audiolab.play(mixed, fs=44100)

If this causes the audio signal to clip (you hear clicks / pops), you may need to pre-scale the data before mixing:

mixed = frames1 / 2 + frames2 / 2

.. and if the sounds do not have equal length, it may take a little more work:

mixed = np.zeros(max(len(frames1), len(frames2)), dtype=frames1.dtype)
mixed[:len(frames1)] += frames1 / 2
mixed[:len(frames2)] += frames2 / 2

OTHER TIPS

The better way to approach this is to use a library that already knows how to mix audio streams -- two different processes trying to share the audio hardware is at best a wonky way to address this problem.

Look at Pygame or PyAudio (Python bindings to PortAudio).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top