[PyQt] pyqt4 amd multiprocessing

Samuele Carcagno sam.carcagno at gmail.com
Mon May 9 11:26:14 BST 2011


Hi, 

I would like to use the multiprocessing module to create a set of sounds (as numpy arrays) in parallel.
The parameters of the sounds (duration, volume, etc..) are controlled by a pyqt4 GUI, and the sounds
need to be passed back to the GUI for further processing and presentation. The sounds are generated
in a separate module from the GUI. I'm attaching a minimal example with a file that creates the gui and
a second file that contains the functions for generating the sounds.

I've had mixed success so far, it seems to work on Kubuntu Natty - Python 2.7.1+ - Qt 4.7.2 - PyQt 4.8.3 
but sometimes it fails on Kubuntu Lucid -  Python 2.6.5 - Qt 4.6.2 - PyQt 4.7.2  with the following error:

Traceback (most recent call last):
  File "test_gui.py", line 20, in onClickButton1
    self.doTrial()
  File "test_gui.py", line 32, in doTrial
    x = complexTone(F0, lowHarm, highHarm, level, duration, ramp, channel, fs, maxLevel)
  File "/media/ntfsShared/mptest/simple_test/stim.py", line 45, in complexTone
    pool.join()
  File "/usr/lib/python2.6/multiprocessing/pool.py", line 342, in join
    p.join()
  File "/usr/lib/python2.6/multiprocessing/process.py", line 119, in join
    res = self._popen.wait(timeout)
  File "/usr/lib/python2.6/multiprocessing/forking.py", line 117, in wait
    return self.poll(0)
  File "/usr/lib/python2.6/multiprocessing/forking.py", line 106, in poll
    pid, sts = os.waitpid(self.pid, flag)
OSError: [Errno 4] Interrupted system call

Am I doing something fundamentally unsafe by using multiprocessing in this way with a pyqt4 GUI?
What is the best approach to use multiprocessing together with pyqt4?

Thanks for any suggestions!

Sam

###---------GUI----------File 1
from PyQt4 import QtGui
from PyQt4 import QtCore
import sys
from stim import* #import module for stimulus generation


class Example(QtGui.QWidget):
  
    def __init__(self):
        super(Example, self).__init__()
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Multiprocessing Test')

        self.button1 = QtGui.QPushButton('Button 1', self)
        QtCore.QObject.connect(self.button1,
                               QtCore.SIGNAL('clicked()'), self.onClickButton1)

    def onClickButton1(self):
        self.doTrial()

    def doTrial(self):
        F0 = 200
        lowHarm=1
        highHarm = 20
        level = 50
        duration = 180
        ramp = 10
        channel = "Both"
        fs = 44100
        maxLevel = 100.0
        x = complexTone(F0, lowHarm, highHarm, level, duration, ramp, channel, fs, maxLevel)
        

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_()
#----------END OF FILE 1


###-SOUND GENERATION-- File stim.py
from numpy import*
import multiprocessing

def pureTone(frequency, phase, level, duration, ramp, channel, fs, maxLevel):

    amp = 10**((level - maxLevel) / 20.)
    duration = duration / 1000. #convert from ms to sec
    ramp = ramp / 1000.

    nSamples = int(round(duration * fs))
    nRamp = int(round(ramp * fs))
    nTot = nSamples + (nRamp * 2)

    timeAll = arange(0., nTot) / fs
    timeRamp = arange(0., nRamp) 

    snd = zeros((nTot, 2))

    if channel == "Right":
        snd[0:nRamp, 1] = amp * ((1-cos(pi * timeRamp/nRamp))/2) * sin(2*pi*frequency * timeAll[0:nRamp] + phase)
        snd[nRamp:nRamp+nSamples, 1] = amp* sin(2*pi*frequency * timeAll[nRamp:nRamp+nSamples] + phase)
        snd[nRamp+nSamples:len(timeAll), 1] = amp * ((1+cos(pi * timeRamp/nRamp))/2) * sin(2*pi*frequency * timeAll[nRamp+nSamples:len(timeAll)] + phase)
    elif channel == "Left":
        snd[0:nRamp, 0] = amp * ((1-cos(pi * timeRamp/nRamp))/2) * sin(2*pi*frequency * timeAll[0:nRamp] + phase)
        snd[nRamp:nRamp+nSamples, 0] = amp* sin(2*pi*frequency * timeAll[nRamp:nRamp+nSamples] + phase)
        snd[nRamp+nSamples:len(timeAll), 0] = amp * ((1+cos(pi * timeRamp/nRamp))/2) * sin(2*pi*frequency * timeAll[nRamp+nSamples:len(timeAll)] + phase)
    elif channel == "Both":
        snd[0:nRamp, 0] = amp * ((1-cos(pi * timeRamp/nRamp))/2) * sin(2*pi*frequency * timeAll[0:nRamp] + phase)
        snd[nRamp:nRamp+nSamples, 0] = amp* sin(2*pi*frequency * timeAll[nRamp:nRamp+nSamples] + phase)
        snd[nRamp+nSamples:len(timeAll), 0] = amp * ((1+cos(pi * timeRamp/nRamp))/2) * sin(2*pi*frequency * timeAll[nRamp+nSamples:len(timeAll)] + phase)
        snd[:, 1] = snd[:, 0] 

    return snd


def complexTone(F0, lowHarm, highHarm, level, duration, ramp, channel, fs, maxLevel):
    pool = multiprocessing.Pool()
    tn = []

    for i in range(lowHarm, highHarm+1):
        res = pool.apply_async(pureTone, (F0*i, 0, level, duration, ramp, channel, fs, maxLevel,), callback=tn.append)
   
    pool.close()
    pool.join()
    
    for i in range(len(tn)):
        if i == 0:
            snd = tn[i]
        else:
            snd = snd + tn[i]

    return snd

#----------END OF FILE 2


More information about the PyQt mailing list