-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMixed_detection_code.py
More file actions
706 lines (603 loc) · 24.5 KB
/
Mixed_detection_code.py
File metadata and controls
706 lines (603 loc) · 24.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
########
#Important parameters
########
viewing_distance = 2.0 #units can be anything so long as they match those used in screen_width below
screen_width = 1.0 #units can be anything so long as they match those used in viewing_distance above
screen_res = (1920,1080) #pixel resolution of the screen
#viewing_distance = 3.0 #units can be anything so long as they match those used in screen_width below
#screen_width = 1.0 #units can be anything so long as they match those used in viewing_distance above
#screen_res = (1366,768) #pixel resolution of the screen
background_noise_volume = .1
response_keys = ['z','/']
response_triggers = [4,5]
soa_list = [0.400,1.600]
cue_list = ['valid','valid','valid','valid','invalid']
target_list = ['black','white']
signal_list = ['lo','hi']
fixation_min = 2.000
fixation_mean = 4.000
fixation_max = 10.000
signal_duration = 0.100
response_timeout = 1.000
ITI = 1.000
num_blocks = 12
instruction_size_in_degrees = 1 #specify the size of the instruction text
feedback_size_in_degrees = .5 #specify the size of the feedback text
target_size_in_degrees = .5 #specify the width of the target
text_width = .9 #specify the proportion of the screen to use when drawing instructions
circle_slices = 12 #specify the number of slices in the fixation/target circle
########
# Import libraries
########
import pygame
import numpy as np
from PIL import Image
import aggdraw
import math
import sys
import os
import random
import time
import shutil
########
# Start the random seed
########
seed = time.time() #grab the current time
random.seed(seed) #use the time to set the random seed
########
# Initialize pygame
########
sound_sample_rate = 22050
pygame.mixer.pre_init( frequency=sound_sample_rate, size=-16, channels=2, buffer=4096)
pygame.init() #initialize pygame
pygame.mouse.set_visible(False) #make the mouse invsoable
########
# Initialize the joystick
########
joystick = pygame.joystick.Joystick(0)
joystick.init()
########
# Initialize the sounds
########
# stereo_sound = pygame.mixer.Sound('./_Stimuli/pink_stereo.wav')
# mono_sound = pygame.mixer.Sound('./_Stimuli/pink_mono.wav')
# stereo_sound.set_volume(1)
# mono_sound.set_volume(1)
# sounds_dict = {'stereo':stereo_sound.play(-1),'mono':mono_sound.play(-1)}
# sounds_dict['mono'].pause()
# sounds_dict['stereo'].pause()
#
########
# Initialize the screen
########
screen = pygame.display.set_mode(screen_res, pygame.FULLSCREEN | pygame.HWSURFACE | pygame.DOUBLEBUF) #initialize a screen
screen_x_center = screen_res[0]/2 #store the location of the screen's x center
screen_y_center = screen_res[1]/2 #store the location of the screen's y center
########
#Perform some calculations to convert stimulus measurements in degrees to pixels
########
screen_width_in_degrees = math.degrees(math.atan((screen_width/2.0)/viewing_distance)*2)
PPD = screen_res[0]/screen_width_in_degrees #compute the pixels per degree (PPD)
instruction_size = int(instruction_size_in_degrees*PPD)
feedback_size = int(feedback_size_in_degrees*PPD)
target_size = int(target_size_in_degrees*PPD)
########
#Define some useful colors
########
black = (0,0,0)
white = (255,255,255)
grey = (119,119,119)
########
#Initialize the fonts
########
instruction_font_size = 2
instruction_font = pygame.font.Font('_Stimuli/DejaVuSans.ttf', instruction_font_size)
instruction_height = instruction_font.size('XXX')[1]
while instruction_height<instruction_size:
instruction_font_size = instruction_font_size + 1
instruction_font = pygame.font.Font('_Stimuli/DejaVuSans.ttf', instruction_font_size)
instruction_height = instruction_font.size('XXX')[1]
instruction_font_size = instruction_font_size - 1
instruction_font = pygame.font.Font('_Stimuli/DejaVuSans.ttf', instruction_font_size)
instruction_height = instruction_font.size('XXX')[1]
feedback_font_size = 2
feedback_font = pygame.font.Font('_Stimuli/DejaVuSansMono.ttf', feedback_font_size)
feedback_height = feedback_font.size('XXX')[1]
while feedback_height<feedback_size:
feedback_font_size = feedback_font_size + 1
feedback_font = pygame.font.Font('_Stimuli/DejaVuSansMono.ttf', feedback_font_size)
feedback_height = feedback_font.size('XXX')[1]
feedback_font_size = feedback_font_size - 1
feedback_font = pygame.font.Font('_Stimuli/DejaVuSansMono.ttf', feedback_font_size)
feedback_height = feedback_font.size('XXX')[1]
feedback_eraser_size = feedback_font.size('XXXXXXX\nXXXXXXX\nXXXXXXX')
feedback_eraser = pygame.Surface((feedback_eraser_size[0],feedback_eraser_size[1]))
feedback_eraser.fill(grey)
########
# Create sprites for visual stimuli
########
#define a function to turn PIL/aggdraw images to pygame surfaces
def image2surf(image):
mode = image.mode
size = image.size
data = image.tostring()
return pygame.image.fromstring(data, size, mode)
white_circle = aggdraw.Draw('RGBA',[target_size,target_size],grey)
white_circle.ellipse([0,0,target_size,target_size],aggdraw.Brush(white))
white_circle = image2surf(white_circle)
black_circle = aggdraw.Draw('RGBA',[target_size,target_size],grey)
black_circle.ellipse([0,0,target_size,target_size],aggdraw.Brush(black))
black_circle = image2surf(black_circle)
circle_eraser = pygame.Surface((target_size*2,target_size*2))
circle_eraser.fill(grey)
#create cue sprites
short_cue = feedback_font.render('S', True, [0,0,255])
long_cue = feedback_font.render('L', True, [0,0,255])
########
# Helper functions
########
#define a function to draw a pygame surface centered on given coordinates
def blit_to_screen(surf,x_offset=0,y_offset=0):
x = screen_x_center+x_offset-surf.get_width()/2.0
y = screen_y_center+y_offset-surf.get_height()/2.0
screen.blit(surf,(x,y))
#define a function to return the pygame time in seconds
def pytime():
return time.time()#pygame.time.get_performance_counter()/1000000.0
#define a function that waits for a given duration to pass
def simple_wait(duration):
start = pytime()
while pytime() < (start + duration):
pass
#define a function that formats text for the screen
def draw_text(my_text, instruction_font, text_color, my_surface, text_width):
my_surface_rect = my_surface.get_rect()
text_width_max = int(my_surface_rect.size[0]*text_width)
paragraphs = my_text.split('\n')
render_list = []
text_height = 0
for this_paragraph in paragraphs:
words = this_paragraph.split(' ')
if len(words)==1:
render_list.append(words[0])
if (this_paragraph!=paragraphs[len(paragraphs)-1]):
render_list.append(' ')
text_height = text_height + instruction_font.get_linesize()
else:
this_word_index = 0
while this_word_index < (len(words)-1):
line_start = this_word_index
line_width = 0
while (this_word_index < (len(words)-1)) and (line_width <= text_width_max):
this_word_index = this_word_index + 1
line_width = instruction_font.size(' '.join(words[line_start:(this_word_index+1)]))[0]
if this_word_index < (len(words)-1):
#last word went over, paragraph continues
render_list.append(' '.join(words[line_start:(this_word_index-1)]))
text_height = text_height + instruction_font.get_linesize()
this_word_index = this_word_index-1
else:
if line_width <= text_width_max:
#short final line
render_list.append(' '.join(words[line_start:(this_word_index+1)]))
text_height = text_height + instruction_font.get_linesize()
else:
#full line then 1 word final line
render_list.append(' '.join(words[line_start:this_word_index]))
text_height = text_height + instruction_font.get_linesize()
render_list.append(words[this_word_index])
text_height = text_height + instruction_font.get_linesize()
#at end of paragraph, check whether a inter-paragraph space should be added
if (this_paragraph!=paragraphs[len(paragraphs)-1]):
render_list.append(' ')
text_height = text_height + instruction_font.get_linesize()
num_lines = len(render_list)*1.0
for this_line in range(len(render_list)):
this_render = instruction_font.render(render_list[this_line], True, text_color)
this_render_rect = this_render.get_rect()
this_render_rect.centerx = my_surface_rect.centerx
this_render_rect.centery = int(my_surface_rect.centery - text_height/2.0 + 1.0*this_line/num_lines*text_height)
my_surface.blit(this_render, this_render_rect)
#define a function that will kill everything safely
def exit_safely():
pygame.quit()
try:
data_file.close()
except:
pass
sys.exit()
#define a function that waits for a response
def wait_for_response(key=None):
pygame.event.clear()
done = False
while not done:
pygame.event.pump()
for event in pygame.event.get() :
if event.type == pygame.KEYDOWN :
response = event.unicode
if response == '\x1b':
exit_safely()
else:
if key==None:
done = True
elif response==key:
done = True
pygame.event.clear()
return response
#define a function that prints a message on the screen while looking for user input to continue. The function returns the total time it waited
def show_message(my_text,key=None):
message_viewing_time_start = pytime()
pygame.event.pump()
pygame.event.clear()
screen.fill(black)
pygame.display.flip()
screen.fill(black)
draw_text(my_text, instruction_font, grey, screen, text_width)
simple_wait(.5)
pygame.display.flip()
screen.fill(black)
wait_for_response(key=key)
pygame.display.flip()
screen.fill(black)
simple_wait(.5)
message_viewing_time = pytime() - message_viewing_time_start
return message_viewing_time
#define a function that requests user input
def get_input(get_what):
get_what = get_what+'\n'
text_input = ''
screen.fill(black)
pygame.display.flip()
simple_wait(.5)
my_text = get_what+text_input
screen.fill(black)
draw_text(my_text, instruction_font, grey, screen, text_width)
pygame.display.flip()
screen.fill(black)
done = False
while not done:
pygame.event.pump()
for event in pygame.event.get() :
if event.type == pygame.KEYDOWN :
key_down = event.unicode
if key_down == '\x1b':
exit_safely()
elif key_down == '\x7f':
if text_input!='':
text_input = text_input[0:(len(text_input)-1)]
my_text = get_what+text_input
screen.fill(black)
draw_text(my_text, instruction_font, grey, screen, text_width)
pygame.display.flip()
elif key_down == '\r':
done = True
else:
text_input = text_input + key_down
my_text = get_what+text_input
screen.fill(black)
draw_text(my_text, instruction_font, grey, screen, text_width)
pygame.display.flip()
screen.fill(black)
pygame.display.flip()
return text_input
#define a function that obtains subject info via user input
def get_sub_info():
year = time.strftime('%Y')
month = time.strftime('%m')
day = time.strftime('%d')
hour = time.strftime('%H')
minute = time.strftime('%M')
sid = get_input('ID:')
if sid != 'test':
age = get_input('Age (2-digit number):')
handedness = get_input('Handedness (r or l):')
sex = get_input('Sex (m or f):')
else:
sex='test'
age='test'
handedness='test'
languages = 'test'
music = 'test'
gaming = 'test'
sub_info = [ sid , year , month , day , hour , minute , sex , age , handedness ]
return sub_info
#define a function that initializes the data file
def initialize_data_files():
if not os.path.exists('_Data'):
os.mkdir('_Data')
if sub_info[0]=='test':
filebase = 'test'
else:
filebase = '_'.join(sub_info[0:6])
if not os.path.exists('_Data/'+filebase):
os.mkdir('_Data/'+filebase)
shutil.copy(__file__, '_Data/'+filebase+'/'+filebase+'_code.py')
data_file_name = '_Data/'+filebase+'/'+filebase+'_data.txt'
data_file = open(data_file_name,'w')
header ='\t'.join(['id' , 'year' , 'month' , 'day' , 'hour' , 'minute' , 'sex' , 'age' , 'handedness' , 'wait' , 'block' , 'trial_num' , 'fixation_interval' , 'soa' , 'cue' , 'signal','target' , 'rt' , 'response' , 'error' , 'pre_target_response' , 'ITI_response' ])
data_file.write(header+'\n')
trigger_file_name = '_Data/'+filebase+'/'+filebase+'_trigger.txt'
trigger_file = open(trigger_file_name,'w')
header ='\t'.join(['id' , 'year' , 'month' , 'day' , 'hour' , 'minute' , 'sex' , 'age' , 'handedness' , 'block' , 'trial_num' , 'signal' , 'trigger' , 'time' , 'value' ])
trigger_file.write(header+'\n')
return data_file, trigger_file
#define a function to generate a fixation interval
def get_fixation_interval():
fixation_interval = random.expovariate(1/(fixation_mean-fixation_min))+fixation_min
while fixation_interval>fixation_max:
fixation_interval = random.expovariate(1/(fixation_mean-fixation_min))+fixation_min
return fixation_interval
#define a function that generates a randomized list of trial-by-trial stimulus information representing a factorial combination of the independent variables.
def get_trials(block):
trials=[]
for soa in soa_list:
for target in target_list:
for cue in cue_list:
for signal in signal_list:
fixation_interval = get_fixation_interval()
trials.append([fixation_interval,soa,cue,target,signal])
random.shuffle(trials)
return trials
#define a function that runs a block of trials
def run_block(block,message_viewing_time):
#start the background noise looping
#sounds_dict['mono'].set_volume(background_noise_volume)
#sounds_dict['mono'].unpause()
#start the signal looping
#stereo_sound.set_volume(0)
#stereo_sound.play(-1)
#stereo_sound.pause()
#get a trial list
trial_list = get_trials(block)
trial_num = 0
#start running trials
while len(trial_list)>0:
#bump the trial number
trial_num = trial_num + 1
#parse the trial info
fixation_interval, soa, cue, target, signal = trial_list.pop(0)
#generate the sound arrays
max_int = 2**16/4
pre_cue = np.random.randint(-max_int,max_int,fixation_interval*sound_sample_rate)
if signal=='hi':
signal_multiplier = 2
else:
signal_multiplier = 1
cue_L = np.random.randint(-max_int*signal_multiplier,max_int*signal_multiplier,signal_duration*sound_sample_rate)
cue_R = np.random.randint(-max_int*signal_multiplier,max_int*signal_multiplier,signal_duration*sound_sample_rate)
post_cue = np.random.randint(-max_int,max_int,10*sound_sample_rate)
L = np.concatenate((pre_cue,cue_L,post_cue))
R = np.concatenate((pre_cue,cue_R,post_cue))
arr = np.c_[L,R]
try:
snd.stop()
except:
pass
snd = pygame.sndarray.make_sound(arr.astype(np.int16))
#snd.set_volume(1)
snd.play(1)
pygame.event.pump()
if cue=='valid':
if soa==soa_list[0]:
cue_stim = short_cue
else:
cue_stim = long_cue
else:
if soa==soa_list[0]:
cue_stim = long_cue
else:
cue_stim = short_cue
done = False
while not done:
if pygame.mixer.get_busy():
done = True
#start the trial by showing the fixation screen
screen.fill(grey)
blit_to_screen(cue_stim)
pygame.display.flip() #this might not block
screen.fill(grey)
blit_to_screen(cue_stim)
pygame.display.flip() #this should block
pygame.event.clear()
#get the trial start time and compute event times
trial_start_time = pytime() - 1/60.00 #one frame in the past
cue_on_time = trial_start_time + fixation_interval
cue_off_time = cue_on_time + signal_duration
target_on_time = cue_on_time + soa
target_off_time = target_on_time + response_timeout
#prep the target screen
screen.fill(grey)
if target=='white':
blit_to_screen(white_circle)
else:
blit_to_screen(black_circle)
#prep some variables
pre_target_response = 'FALSE'
ITI_response = 'FALSE'
response = 'NA'
rt = 'NA'
error = 'NA'
cue_started = False
cue_done = False
target_started = False
target_done = False
trial_done = False
left_trigger_vals = []
right_trigger_vals = []
while not trial_done:
# if not cue_started:
# if pytime()>=cue_on_time:
# cue_started = True
# if signal=='lo':
# sounds_dict['stereo'].set_volume(background_noise_volume)
# else:
# sounds_dict['stereo'].set_volume(background_noise_volume*10)
# sounds_dict['stereo'].unpause()
# sounds_dict['mono'].pause()
# pygame.event.pump()
# print ['cue start',pytime()-cue_on_time]
# elif not cue_done:
# if pytime()>=cue_off_time:
# cue_done = True
# sounds_dict['mono'].unpause()
# sounds_dict['stereo'].pause()
# pygame.event.pump()
# print ['cue done',pytime()-cue_off_time]
# el
if not target_started:
if pytime()>=target_on_time:
target_started = True
pygame.display.flip()
elif not target_done:
if pytime()>=target_off_time:
target_done = True
trial_done = True
response = 'NA'
error = 'NA'
rt = 'NA'
feedback_text = 'Miss!'
feedback_color = [255,0,0]
ITI_done_time = target_off_time + ITI
pygame.event.pump()
now = pytime()-target_on_time
for event in pygame.event.get():
if event.type == pygame.JOYAXISMOTION:
if event.axis in response_triggers:
if event.axis==response_triggers[0]:
left_trigger_vals.append([now,event.value])
else:
right_trigger_vals.append([now,event.value])
if event.value>0:
trial_done = True
if not target_started:
ITI_done_time = now + ITI
trial_done = True
pre_target_response = 'TRUE'
feedback_text = 'Too soon!'
feedback_color = [255,0,0]
else:
response = event.axis
rt = now
feedback_text = str(int(round(rt*10)))
ITI_done_time = pytime() + ITI
if response==black_response:
response = 'black'
elif response==white_response:
response = 'white'
else:
feedback_color = [255,0,0]
feedback_text = 'wrong keys!'
if target=='black':
feedback_color = black
elif target=='white':
feedback_color = white
if response == target:
error = 'FALSE'
elif ((response=='black') or (response=='white')):
error = 'TRUE'
else:
error = 'NA'
elif event.type == pygame.KEYDOWN :
trial_done = True
if event.unicode == '\x1b':
exit_safely()
elif not target_started:
ITI_done_time = now + ITI
trial_done = True
pre_target_response = 'TRUE'
feedback_text = 'Too soon!'
feedback_color = [255,0,0]
else:
response = event.unicode
rt = now
feedback_text = str(int(round(rt*10)))
ITI_done_time = pytime() + ITI
if response==black_response:
response = 'black'
elif response==white_response:
response = 'white'
else:
feedback_color = [255,0,0]
feedback_text = 'wrong keys!'
if target=='black':
feedback_color = black
elif target=='white':
feedback_color = white
if response == target:
error = 'FALSE'
elif ((response=='black') or (response=='white')):
error = 'TRUE'
else:
error = 'NA'
#make sure the sounds have reset
#sounds_dict['mono'].unpause()
#sounds_dict['stereo'].pause()
#present the feedback screen
blit_to_screen(circle_eraser)
rendered_feedback_text = feedback_font.render(feedback_text, True, feedback_color)
blit_to_screen(rendered_feedback_text)
pygame.display.flip()
while pytime()<ITI_done_time:
pygame.event.pump()
now = pytime()-target_on_time
for event in pygame.event.get():
if event.type == pygame.JOYAXISMOTION:
if event.axis in response_triggers:
if event.axis==response_triggers[0]:
left_trigger_vals.append([now,event.value])
else:
right_trigger_vals.append([now,event.value])
elif event.type == pygame.KEYDOWN :
if event.unicode == '\x1b':
exit_safely()
else:
if feedback_text=='Miss!':
feedback_text = 'Too slow!'
else:
feedback_text = 'Too many!'
ITI_response = 'TRUE'
ITI_done_time = pytime() + ITI
blit_to_screen(feedback_eraser)
rendered_feedback_text = feedback_font.render(feedback_text, True, [255,0,0])
blit_to_screen(rendered_feedback_text)
pygame.display.flip()
#write out data
for i in left_trigger_vals:
trial_info = '\t'.join(map(str,[sub_info_for_file, block, trial_num, signal, 'left' , i[0], i[1]]))
trigger_file.write(trial_info+'\n')
for i in right_trigger_vals:
trial_info = '\t'.join(map(str,[sub_info_for_file, block, trial_num, signal, 'right' , i[0], i[1]]))
trigger_file.write(trial_info+'\n')
trial_info = '\t'.join(map(str, [ sub_info_for_file , message_viewing_time , block , trial_num , fixation_interval , soa , cue , signal , target , rt , response , error , pre_target_response , ITI_response]))
data_file.write(trial_info+'\n')
#sounds_dict['mono'].pause()
#sounds_dict['stereo'].pause()
snd.stop()
########
# Start the experiment
########
#get subject info
sub_info = get_sub_info()
sub_info_for_file = '\t'.join(map(str,sub_info))
#initialize the data file
data_file,trigger_file = initialize_data_files()
#black_response = response_keys[0]
#white_response = response_keys[1]
black_response = response_triggers[0]
white_response = response_triggers[1]
#message_viewing_time = show_message('In this experiment your job is to watch for the appearance of white and black circles. \nWhen you see a black circle, press the "z" key with your left index finger.\nWhen you see a white circle, press the "/" key with your right index finger.\nWhen the circles appear, try to respond as quickly as you can. Try not to make too many errors, but responding quickly is most important.\nWhen you are ready to proceed to the next page of instructions, press the "Y" key.','y')
message_viewing_time = show_message('In this experiment your job is to watch for the appearance of white and black circles. \nWhen either circle appears, press down on both the left and right triggers of the gamepad. \nWhen the circles appear, try to respond as quickly as you can. Try not to make too many errors, like responding too early, but responding quickly is most important.\nWhen you are ready to proceed to the next page of instructions, press the "Y" key.','y')
message_viewing_time = show_message('To help you monitor how quickly and accurately you\'re responding, a number will appear showing how long it took you to respond (in tenths of a second). You want this number to be as SMALL as possible, ideally between 2 and 6.\nWhen you are ready to proceed to the next page of instructions, press the "Y" key.','y')
message_viewing_time += show_message('Throughout the experiment you will hear a fuzz sound through the headphones. We would like for the volume to be the same for everyone, so try not to adjust this. If you need to reduce or increase the volume, please let the experimentor know and they will change it for you.\nThe fuzz sound will change slightly before the circles appear, providing you with a warning to get ready for the circles.\nWhen you are ready to proceed to the next page of instructions, press the "Y" key.','y')
message_viewing_time += show_message('Sometimes the circles will appear immediately after this warning, but sometimes it will take a moment for the circles to appear. Before the warning occurs, a letter will appear that indicates whether it will be a short time ("S") between the warning and circle, or if it will be a long time ("L") between the warning and circle. Please use the length information while doing the task as this will benefit your performance. \nWhen you are ready to proceed to the next page of instructions, press the "Y" key.','y')
#message_viewing_time += show_message('To give you a feel for how the experiment works, the first few minutes will be considered practice.\n\nRemember:\nWhen you see a black circle, press the "z" key with your left index finger.\nWhen you see a white circle, press the "/" key with your right index finger.\n\nWhen you are ready to begin practice, press "Y" key.','y')
message_viewing_time += show_message('To give you a feel for how the experiment works, the first few minutes will be considered practice.\n\nRemember:\nRespond by pressing BOTH triggers down.\nThe "S" means "short" and the "L" means "long". Use these letters to help you respond as quick as possible.\n\nWhen you are ready to begin practice, press "Y" key.','y')
run_block(block='practice',message_viewing_time=message_viewing_time)
message_viewing_time = show_message('Practice is complete.\nWhen you are ready to continue to the experiment, press the "Y" key.','y')
for i in range(num_blocks):
block = i + 1
run_block(block=block,message_viewing_time=message_viewing_time)
if block<num_blocks:
message_viewing_time = show_message('Take a break!\nYou are '+str(block)+'/'+str(num_blocks)+' done the experiment.\nWhen you are ready to resume the experiment, press the "Y" key.','y')
message_viewing_time = show_message('You\'re all done!\nPress the "Y" key to quit the experiment, after which you are free to quietly use your phone or the computuer. The experimentor will let you know when everyone is done and you can leave','y')
exit_safely()