psychopy.org | Reference | Downloads | Github

Randomising images, ITIs, with randomised musical conditions playing continuously in the background

OS (e.g. Win10): Win10
PsychoPy version (e.g. 1.84.x): 3.2.4
**Standard Standalone? yes, win 64bit
What are you trying to achieve?:

I’m helping program an experiment that consists of 54 images that are divided into 3 conditions - neutral, negative, and positive. They have to be divided into 3 blocks - one block with 18 images (6 of each) and a melody playing in the left ear, one block where there is no melody, and another block with the melody in the right ear. The images have to appear in a random order, but not repeat throughout the experiment in the different block melody conditions. The melody has to run throughout the block continuously in the background. The blocks are also randomised. In addition, the fixation cross/ITI is variable - 6,8, or 10 seconds.

What did you try to make it work?:

I’ve looked through the forum and used this code to randomise the blocks and the images and make sure nothing repeats - it works:

Code component begin experiment:

pos_files = [str(i) +'_pos.png' for i in range(18)]
neg_files = [str(i) +'_neg.png' for i in range(18)]
neu_files = [str(i) +'_neu.png' for i in range(18)]

# randomise their order:
shuffle(pos_files)
shuffle(neg_files)
shuffle(neu_files)

# get now-randomised selections of each for each block:
left = pos_files[0:6] + neg_files[0:6] + neu_files[0:6]
right = pos_files[6:12] + neg_files[6:12] + neu_files[6:12]
none = pos_files[12:18] + neg_files[12:18] + neu_files[12:18]

# randomly intersperse the sound trials:
shuffle(left)
shuffle(right)
shuffle(none)

In the begin routine:

current_file = none.pop()
thisExp.addData('current_file', current_file)

In order to have the music playing in the background, I’ve tried lots of things, main solution I tried was this added as a code component (before the fixation and the stimuli condition, within the main experiment loop):

Begin experiment:

background_sound = sound.Sound('tuneleft.wav')

Begin routine:

if trials_4.thisN == 0:
    background_sound.play()

End routine:

if trials_4.thisN == 17:
    background_sound.stop()

For randomised fixation duration, I created an excel file with the timings and added it as a conditions file on a loop.

What specifically went wrong when you tried that?:

If there is no sound, the experiment runs fine. If I add the sound, it will run with the melody in the background if the whole presentation is sequential, but as soon as I randomise the experiment, the melody distorts. I know it might be related to an issue of the melody being in a While loop. But I don’t have enough advanced programming knowledge to understand what that means exactly.

(Also, as soon as I add the melody code, I get another error - it doesn’t go to the next block and says that stimuli are from an empty list, error like one.pop() - can’t draw from empty list (without sound it’s all fine).)

If I add a full melody as a sound component, it continues running without showing the next fixation or image (alternatively, says I’ve run out of memory).

I’m really pressed for time and at a loss.I have uploaded my psyexp file (at the moment without added sound stimuli), conditions files.

I haven’t even started to try and add breaks between blocks and making sure that doesn’t give me some error.

Maybe I don’t need blocks? One conditions file? Define the melodies in code and then randomise?

I’d appreciate any help and let me know if I need to clarify something - I thought it will be rather straightforward, but this background continuous music just messed things up. Thank you!

conds.xlsx (8.2 KB) Eli_Experiment.psyexp (33.1 KB)

The issue here is that you have (correctly) created three lists of image files (left, right, and none). Each contains 18 entries. In your “begin routine” tab, you pop out an entry from just one of those lists (none), so that list will be empty on the nineteenth trial. You need some way of controlling the order of your blocks, and ensuring that all three get presented. Similarly, you will need to play a different sound stimulus in each block.

none isn’t a great variable name in Python as it is close to the built-in name None. For clarity if other people ever read this code, it might be better to use something like neither or similar.

So start by creating a list to control your condition orders. NB these are just string labels- they are distinct from your actual conditions lists:

Begin Experiment:

# control and randomise block order:
block_order = ['left', 'right', 'neither']
shuffle(block_order)

sound_left = sound.Sound('tuneleft.wav')
sound_right = sound.Sound('tuneright.wav')
sound_playing = False # need to keep track of what is playing

Begin Routine:

# on every 18th trial (including 0), set the block condition 
# (by checking 0 is the remainder when dividing by 18):
if trials_4.thisN % 18 == 0:
    if sound_playing:
        background_sound.stop()

    current_side = block_order.pop()
    if current_side == 'left':
        background_sound = sound_left
        background_sound.play()
        sound_playing = True
    elif current_side == 'right':
        background_sound = sound_right
        background_sound.play()
        sound_playing = True
    else:
        sound_playing = False

thisExp.addData('condition', current_side) # record on every trial

# select stimulus for this trial:
if current_side == 'left':
    current_file = left.pop()
elif current_side == 'right':
    current_file = right.pop()
else:
    current_file = neither.pop() # optionally changed from none.pop()

thisExp.addData('image_file', current_file) # record on every trial

None of this is tested of course, so come back with any issues.

Thank you, Michael! Where would you advise to put the code component in? If I put it as a routine in the main loop (trials_4) before the other mini loops, it will randomise which sound file (or neither) starts playing, but basically one image is chosen and shown as the only stimuli and it just doesn’t stop or go to a different condition. If I put it as a separate routine or part of the condition routine in the smaller loops, it will choose the stimuli randomly, but each sound condition will just run once (so 3 trials all together) and then say current_side = block_order.pop() - can not pop from empty list.

Maybe I’m missing something? I’ve kept the initial code bits I wrote and added your suggestions, should I’ve modified something there as well? Thank you!

That code was designed to work as if you have just one loop controlling your trials (I’m assuming that this is called trials_4) and hence the code component should be added to the first routine inside that loop.

From what you’ve described, a single loop should be sufficient. If you have other loops involved in your task, then you need to explain what they do and ideally provide a screenshot.

Ah, I see. I’ll try that. I do have a loop around each condition that related to the fixation - the researchers want a variable duration ITI, that is a fixation cross, so I din’t know how to do it better than to create an excel sheet with the 3 times (6, 8, and 10s) and add it to a loop set to random.

When I add the code to the first routine, it randomly plays one of the musical files, but then chooses just like 3 stimuli, each shown 3 times (so 9 trials) and then the experiment reaches it’s end. I’ve attached the main loop conditions file that I’ve created based on advice on another post.

conds.xlsx (8.2 KB)

My full code at the moment looks like this:

Begin Experiment

pos_files = [str(i) +’_pos.png’ for i in range(18)]
neg_files = [str(i) +’_neg.png’ for i in range(18)]
neu_files = [str(i) +’_neu.png’ for i in range(18)]

# randomise their order:
shuffle(pos_files)
shuffle(neg_files)
shuffle(neu_files)

# get now-randomised selections of each for each block:
left = pos_files[0:6] + neg_files[0:6] + neu_files[0:6]
right = pos_files[6:12] + neg_files[6:12] + neu_files[6:12]
neither = pos_files[12:18] + neg_files[12:18] + neu_files[12:18]

# randomly intersperse the sound trials:
shuffle(left)
shuffle(right)
shuffle(neither)

# control and randomise block order:
block_order = [‘left’, ‘right’, ‘neither’]
shuffle(block_order)

sound_left = sound.Sound(‘tuneleft.wav’)
sound_right = sound.Sound(‘tuneright.wav’)
sound_playing = False # need to keep track of what is playing

Begin Routine: (as you suggested)

I’m not sure why only 3 images repeated 3 times for each routine get selected.

I managed to get 18 trials (with an inside loop around a routine not connected to a conditions file).

But still only 1 stimuli gets chosen and shown 18 times as opposed to 18 different ones.

Hi. OK, you only need one loop, and one routine (or two, if you want to split the fixation point into a separate routine). The loop doesn’t need to be connected to a conditions file, as you are handling the conditions (the image files and the background sounds) in code. Just set the nReps value of the loop to be 54 (i.e. corresponding to three blocks of 18 trials each).

Get it running like that, and then we’ll sort out the variable fixation point duration.

Michael! You are a star and a saviour! I actually had this idea one evening but forgot to write it down and then blanked! I had separate routines because initially my brief was a little different, and I couldn’t move past that initial design. This works!

How should I go regarding variable fixation best? Initially I had a condition file with the times and randomised it. And I can add a break after each block with a line of code too? I think I saw a few topics in the forum on how to do it.

I am so relieved now.

The easiest thing to do here would be to have a conditions file with 54 rows containing your fixation duration values. Then set your loop to have nReps of 1 and to be randomised. The only issue here is that the duration values won’t be perfectly balanced across your three blocks: they will be randomly presented across the entire session. This Probably isn’t an issue if you have a reasonable number of subjects. But if your design does require balancing across blocks, then you would need to implement the duration values in code along with the other conditions.

To have a pause after each block, insert another routine and put this code in the “begin routine” tab of its code component:

if not(your_loop_name.thisN > 0 and your_loop_name.thisN % 18 == 0):
    continueRoutine = False

NB This technique is (hopefully) temporarily broken for PsychoPy versions > 3.2.0, so see here for a temporary workaround:

Thank you, Michael. The workaround regarding the break works!
And maybe I can get away with the fixation not equally distributed. It would all work, except I would need to make sure the music also stops during the break (it now continues during the break and the first fixation in next block and then changes once the new picture appears). Any ideas? I thought maybe also do like sound_playing = False in the begin routine, but that’s not it. Also, would need the music to start playing once the first fixation appears - if I add the fixation in the same routine as the images, everything gets randomised and I’ll get 3 fixations in a row. This is how the builder looks now: