Search code examples
csvaudioframespsychopy

Psychopy Sounds played from a csv file blend together (time measured in frames)


in the experiment I am preparing sounds are played from a csv file and timing is measured in frames. Given the fact that each sound lasts 300ms this equals to 18 frames.

from psychopy import data
from psychopy import core, visual, gui, data, event
from psychopy.tools.filetools import fromFile, toFile
import numpy, random, csv, time
from psychopy import logging, prefs
prefs.general['audioLib'] = ['pyo']  # Set the Audio Library [pyo (highest performer, check it), sounddevice (looks promessing, check it) or pygame (not good with timing)]
prefs.general['audioDriver']=['coreaudio']
from psychopy import sound


win = visual.Window([400,300], monitor="testMonitor", units="cm", fullscr=False)
stimuli = []
datafile = open("audioStim.csv", "rb")
reader = csv.reader(datafile, delimiter=";")
for row in reader:
    stimuli.append(row[0])
    #print (stimuli)
datafile.close()

clock = core.Clock()
for stimulus in stimuli:
    #print (stimuli)
    for frameN in range(18):
        #print clock.getTime()
        sound_stimulus = sound.Sound(stimulus)
        sound_stimulus.play()
        win.callOnFlip(clock.reset)
        win.flip()



## Closing Section
win.close()
core.quit()

When running the experiment the sounds seem to blend with each other. They do not sound discrete. The result is a bit problematic, is this an issue with Psychopy (not good quality when sounds are so short?) or with the code?

Thank you for your time! Any other recommendations or suggestions for improvement of the code are very welcome.


Solution

  • Your code starts playing a sound on each frame, i.e., 60 times a second. Do this:

    for stimulus in stimuli:
        #print (stimuli)
        for frameN in range(18):
            #print clock.getTime()
            win.flip()
            if frameN == 0:
                sound_stimulus = sound.Sound(stimulus)
                sound_stimulus.play()
                clock.reset()  # Time zero is stimulus onset
    

    I did two things here. First, I only start the sound_stimulus.play() and clock.reset() at flip onset only - not at subsequent updatings. Second, I started the sound AFTER win.flip so that it is timed to the flip. If you play before the flip, the sound can start can be anywhere in the 16.7 ms interval (but probably only will be for the very first trial).

    BTW, since you don't really use the variable sound_stimulus, you could simplify the code even further:

            if frameN == 0:
                sound.Sound(stimulus).play()