Timing issue when creating a manual mouse response

Hi everyone,

I’m creating a dual task consisting of a visual search and auditory oddball task. Initially I was using the tick box on the mouse component to end routine when a valid click occurred, however this was cutting off some of the sounds playing, if the respondent clicked the valid visual search target partway through an oddball task. To rectify this issue, I’ve created a manual mouse component using an if statement.

if mouse.getPressed()[0] == True:
    print ("got pressed")
    if gotValidClick == True:
        continueRoutine = False

However it doesn’t seem to be initialising instantly. I click on my target and nothing happens, I click again and it works. If you do a traditional double click, everything is fine. if I wait half a second, it seems to work. If you click to quickly however, the routine doesn’t end. I;ve compared this vs method I was using before using the tick box in the mouse component and it works fine. Has anyone else experienced any timing issues?

Kind regards,

Rob

Where does gotValidClick come from?

Hi Carter,

It comes from my clickable stimuli, which is my only target regarding the mouse. Please see image below.

Kind regards,

Rob

It wouldn’t surprise me if your code reacts to a mouse click on the frame after the mouse click on the Target.

However, I’m not sure how this code is supposed to stop the sounds cutting off.

Hi Carter,

I think you maybe right. If I hold the mouse button down, it works perfectly, but the reaction isn’t instant. For now I will leave the mouse as is. I have compared the reaction times of both the tick box vs my own coded end routine and the RT appear equivalent.

Let me see if I can add some more context to the stopping sound problem. previously I just had the mouse component and have the routine end on click. This worked perfectly for what I wanted, the timing felt correct etc, however if the sound was playing and you clicked the target, it would cut the sound off.

Thus instead of having the automated tick box click from the mouse component ending the routine, I thought a way I could do it, is create a series of IF statements, checking if mouse has been clicked, is it valid, and finally checking if sound is playing, and only end the routine once the sound has stopped playing.

Unless you think it would be simpler use the tick box mouse component end routine and just add a code snippet relating to the sound playing? I know you’re vastly more experience in Python than I am!

Kind regards,

Rob

This is how I would do it. I would create the sound in a component with 0 volume in a previous routine (within the loop if the sound updates for each trial). Then for the actual trial routine set the sound to 1 and play the sound in code

sound_1.setVol(1)
sound_1.play()

This sound will keep playing after the trial ends. I assume there is sufficient gap before the next trial to stop them overlapping.

Hi Carter,

That makes sense. There is definitely time as I have a 0.5s fixation dot between each trial and my sounds last for .05 seconds, however it doesn’t matter in relation to the visual search task as I should note the is the visual search task, and the auditory oddball task are independent of each other (or I am trying to have them as independent as possible) hence needing the oddball task to not be cut if a visual search response is made, but a new trial to begin for the visual search task!

My first Loop before anything is setting up the tones for the auditory oddball task which is just two differing sound components, then an excel sheet of condition, two columns the first being condition normal or oddball (so Psychopy knows which sound to play) and then a second column for time which will result in tones being played for 5 minutes, either normal or oddball. This column consists of differing Inter stimulus intervals ranging between 1-3 seconds to prevent any learning or anticipation. I only have 1 rep of this excel sheet since it is all I need for my Oddball task, as it’s set via time, not number of reps.

I then move onto instructions and finally running the trials which creates and draws stimuli as well as plays the sound. I am playing the sound based off a clock that is created which checks to see if the time matches the one specified on the excel sheet, if yes, then the sound is played. then moves onto the next tone and onset time.

Thank you for the advice, I will see if I can implement it this afternoon.

Hi Carter,

I tried implementing what you suggested however, the sound is still being cut off when clicking on the visual search stimuli. I couldn’t used .setVol(1) for my sound components as I’m using the PTB engine and it was creating an error, so I checked the documentation. I used target_tone.volume = 1 however, which works, but the sound is still being cut off!

Kind regards,

Rob

Hi Rob,

Please could you show your flow and sound related code components so I can see how you are implementing my suggestion?

Best wishes

Wakefield

Hi Wakefield,

Sure. So I did some playing around with if/elif statements and managed to get it to work to some degree, in that the sounds keep playing even if a mouse response is made partway though. I still have the issue of the mouse response on the frame after, however looking at the timing data, it is nearly identical .07 vs .06 reaction times. I’ve attached my code below so you can see. (I’m 99.999% sure I likely have not implemented it correctly!) I’ll attach a series of screen shots so you can see how I’m running the code. Also if it’s easier I can send you the file!

Here I set up the sounds, and I set the volume to 0 as suggested.

This is the flow of the trial. The top two code components are first to play the tones in relation to when they are requested based off my excel spreadsheet. The second code component DrawAll has most of my code for setting up my stimuli and drawing it) I set up all the stimuli before the routine. The rest is creating the target and the mouse response for the visual stimuli and keyboard response for the oddball. I also have end routine on mouse click in the mouse component selected to never.

Here is the code where I play the sounds. it checks every frame what the time is, and when the time is correct, it either plays a target tone or standard tone according to the data from the excel spreadsheet.

Finally the code which checks if the mouse has been pressed. it is a valid response, then wait until sound is stopped and move onto the next trial.

Thank you for all the help so far. I have been getting frustrated in my lack of timely progress in the recent weeks, but your comments and advice keep me going and trying new things.

Kind regards,

Rob

If you start a sound in code (which you’ve previously set up in a component) then there’s no need to wait for the sound to end before you end the routine. You could add an ISI routine to give sufficient gap between trials for any sounds to end.

Why do you have an ImportToneTrials loop? Without an outer loop, only one sound will be assigned to the two tones by the time you reach the trials_loop.

Also, why is the DrawAll code component Python only. Personally, I like using Auto to help check my syntax, even when I’m not pushing online.

Hi Wakefield,

The reason I wait, is because depending on how quickly the participant responds, hypothetically speaking they could find my targets quickly, which may cut the sound duration e.g. from .5s to .25s. They should be familiar with oddball and target tones. however if the tone is only played briefly and during the training it was played for .5 seconds, they may not respond correctly to the tone, thus confounding by oddball task.

The ImportToneTrials loop sets up the excel sheet of my conditions for the oddball task. It’s not a truly random order, as true randomness in oddball tasks can cause differing responses between participants .e.g how they anticipate. The onset is somewhat standardised but the ISI between the tones has some variation to again prevent pattern spotting/anticipation. I discussed this with some other researchers who have use oddball tasks in the pasts! As it currently runs, both sounds play when needed.

image

Thank you for the DrawAll code component advice! I am hoping to run the study online to check my workload manipulations to elicit a subjective response, as I will use wearable sensors such as an ECG when doing the experiment in person. The manipulation check will be used to make sure if the ECG doesn’t find any significant differences between conditions (when I’ve built them into the experiment) I know it wasn’t due to poor manipulation, but rather the devices I am assessing lack the sensitivity to detect changes in physiological functioning.

Kind regards,

Rob

Ending a routine shouldn’t cut off a sound if it has been started in code.

However, the main issue I’m seeing at the moment is that according to your flow you repeat setUpSounds 100 times before proceeding to the instructions and search trials, but you don’t seem to be setting up the sounds to an array. I would expect to either see the importToneTrials loop go round all of the routines, or see the setup sounds routine to the left of the search routine in the trials loop, or (if there are only one set of sounds to set up), just have the trials routine point at the spreadsheet.

Hi Wakefield.

Sorry for the slow response.

Ending a routine shouldn’t cut off a sound if it has been started in code
I agree 100% I am unsure why it was happening in my code before I implemented my IF loop. I don’t know enough about Psychopy’s inner workings to be 100% sure. My only guess is that even though the sounds are played in code, because they are set up as components, there is something strange going on?

I would expect to either see the importToneTrials loop go round all of the routine
I only have one set of sounds, standard tone or target tone. I use the excel spreadsheet to tell Psychopy when to play the sound through the trial. So I don’t have 100 conditions. Each of those 1 conditions in the spreadsheet is a sound, and the time the sound should be played, so it’s easier to think of it of a list of trials, e.g. this is a list of 100 trials that should be played during the visual search task (if I have explained that well enough, let me know if I haven’t!)

The setUpSounds routine exists purely to create sounds then create the list that psychopy knows when to play the sound.

As I need it, the current trial I have created of my combined visual search and auditory oddball task works. So before I build out the other conditions, I want to add a questionnaire to measure workload, however once all the trials_loop has finished, I am just seeing a blank screen. Do I manually need to flip the window to draw the survey, since I am no longer using the end routine on mouse click component? The issue is between the NASA-TLX routine and the search trials routine.

I did wonder if it was due to the oddball onset, in that did that need to finish as well which was why I couldn’t see any of my components in the NASA-TLX routine, however when I tried testing this by reducing my excel sheet to just three trials of the auditory oddball task, however I am getting an error stating list index out of range.

I’m surprised im getting this error to some degree because I didn’t tick import importToneTrials as trials. I understand why it’s saying it, that my oddball task has run out of trials, but I don’t understand why it’s ending the experiment early and giving the error, when all control is based off the visual search task - when n number of trials is completed according to the trials_loop end routine and move on to the next part of the experiment.

Kind regards,

Rob

Please could you add me as a developer to your study so I can take a look? Please unprotect the master branch if you’d like me to make edits.

Hi Wakefield,

Thank you so much! Apologies for the radio silence. My partner broke her ankle the day after you sent and had surgery, hence the delay getting back to you. I don’t have Git but I I can send file. A friend who is good at Python helped me a lot recently, so the experiment seems to run pretty well to some degree. I have all 4 workload conditions working and responding as needed and the loop which runs through them works without any errors.

The main thing I am struggling with is figuring out a way to update my oddball trials for each Repeater Loop. of all the trials. When you open the file and look at the builder you’ll see I loop round each routine twice, these are my conditions (Set at 2 just for testing) and I have a loop called Repeater_Loop which repeats all routines (Again set to 2).

My friend helped and instead of Excel sheets I know set up an array of dicts with all trial onset and trial tone types which is the getTrials code. I am happy building six of these for each of my dual tasks, so each participant gets the same order. By issue is, how do I update the Repeater loop, so that it reads the correct array. Would it simply be a piece of code before the routine begins stating something like if Repeater_Loop.thisN == 0 oddballtrials = dictname and repeat for all loops.thisN?

Kind regards,

Rob
VisSec-to be workedon.psyexp (311.6 KB)

Is the issue that you would like to use oddballTrialsLWL1 for one repeater loop and oddballTrialsHWL1 for the other?

If so, then you could, for example, use

oddballtrials = []
oddballtrials.append(oddballTrialsLWL1)
oddballtrials.append(oddballTrialsHWL1)
shuffle(oddballtrials)

then address the items using
oddballtrials[Repeater_Loop.thisN]['variable name']

Hi Wakefield,

Apologies, I did not explain myself very well. I meant having oddballTrialsLWL1 and then similar arrays called oddballTrialsLWL2 and oddballTrialsLWL3 and these would be the oddball tones and onset times for Low workload dual task conditions. So repeater loop 0 would have oddballTrialsLWL1, repeater loop 1 would have oddballTrialsLWL2 and repeater loop 2 would have oddballTrialsLWL3. I have two dual task conditions low and high workload, so I would have a total of 6 arrays of tone type and onset values. 3 for low workload dual task, and 3 for high workload dual task.

I think what you suggested could be adapted though to meet my needs.

oddballtrialsL = []
oddballtrialsL.append(oddballTrialsLWL1)
oddballtrialsL.append(oddballTrialsLWL2)
oddballtrialsL.append(oddballTrialsLWL3)


#no shuffle because I don't need it random

if oddballtrials[Repeater_Loop.thisN] = 0
    oddballtrials =  oddballtrials[0]
elif oddballtrials[Repeater_Loop.thisN] = 1
    oddballtrials =  oddballtrials[1]
else
    oddballtrials =  oddballtrials[2]

and repeat this for the highworkload dual task as well.

I will have a go at implementing this.

The other final thing is, my excel sheet has many columns and isn’t the clearest when I read it. I would like to try and make my life a little easier when it comes to analysis. I was reading a forum post yesterday where instead of automatically recording a mouse click, it was hardcoded instead. In your experience do you think this would be a better approach for me to take, I hardcode whichever data I need to try and get a more condensed output file with only the necessary information?