R.Muralikrishnan, MPI for Empirical Aesthetics. This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Licence. ############################################################################## ## ## ## Polione : Self-paced Reading Study with Strophe Stimuli ## ## and intermittent Probe Task ## ## Experiment Script for use with Presentation ## ## Experimenter : Stefan Blohm ## ## Author: R. Muralikrishnan ## ## ## ############################################################################## /* General Logic / Read the input stimulus. Generate a blanked out stimulus that corresponds / to the original verse. Display the whole strophe in a self-paced manner. / Before displaying the next word, check whether a probe task needs to be / inserted (based on whether the word to present would trigger a probe task). / If so, present the probe task. In the case, once the probe is over, / if the verse is still not over, continue presenting the verse until it is over. / / Conventions expected in the input file / Text phrases to be presented together: joined by _; Eg., Die_Strophe. / Next line indicator: ' +' (A space followed by a plus sign). */ ############################################################################## # Scenario Description Language (SDL) Header Part ############################################################################## # These button codes have to correspond to those set in 'Settings -> Response' active_buttons = 4; # There are 4 active buttons defined in 'Settings -> Response' button_codes = 1,2,3,4; # These are the codes of those buttons response_matching = simple_matching; # Enables features not in legacy_matching # Only those button presses that one expects are logged; not all response_logging = log_active; # Needed for EEG Trigger files ### write_codes = true; ### pulse_width = 5; ### default_output_port = 1; # This is most probably going to be the same for everyone. # This is the LPT Parallel port that you will define in the Port settings tab of # Presentation. This will be used as the output port for sending codes to EEG. # Defining this here saves getting a port number in the PCL part from the output_manager # and calling send_code etc. Stimulus events themselves will send these for us, provided we # define the correct port_codes in each Stimulus event. # Default Settings for Font, FG and BG Colours etc. default_background_color = "0, 0, 0"; # RGB codes in decimal; #000000 => Black default_font = "Consolas";# "Liberation Mono"; # Alternatives: Courier New Bold; default_font_size = 27; default_text_color = "000, 102, 153"; # "000, 102, 153"; # 006699 A pleasant bluish colour default_text_align = align_center; default_deltat = 0; default_picture_duration = next_picture; #/* This implies that all pictures ... #...are shown until the next picture is shown, unless otherwise specified */ #default_all_responses = false; # max_y = 1000; # Scaling of things on screen. The bigger the value, the smaller the text/image. ############################################################################## # Scenario Description Language (SDL) Part ############################################################################## begin; # ============================ # SDL Variable Declarations: - # ============================ # # We don't use any variables. All the timer parameters appear as numbers. # ============================== # Picture Stimuli Definitions: - Everything that is shown, including text! # ============================== # Screen definition for the trial that starts an Experimental Session. # Used as the first screen that the participant sees. Operator Controlled. line_graphic { coordinates = -500, -72, -500, 71; coordinates = 500, -72, 500, 71; coordinates = -500, -70, 500, -70; coordinates = -500, 70, 500, 70; line_width = 4; line_color = 32, 32, 32; } Lin_Border; picture { text { caption = "Willkommen! Gleich geht's los."; max_text_width = 1000;}; x = 0; y = 0; line_graphic Lin_Border; x = 0; y = 0; } P_Start_Exp; # Screen definition for the Pause trial # Operator Controlled! picture { text { caption = "Kurze Pause!"; }; x = 0; y = 0; line_graphic Lin_Border; x = 0; y = 0; } P_Pause; # Screen definition for the Continue trial # Participant Controlled! picture { text { caption = "Bitte zum Fortfahren eine Taste drücken."; max_text_width = 1000;}; x = 0; y = 0; line_graphic Lin_Border; x = 0; y = 0; } P_Continue; # Screen definition for showing the focus star picture { bitmap { filename = "Focus_Star.bmp"; }; # Use Focus_Star.bmp #text {caption = "+"; text_align = align_left; max_text_width = 1200; }; left_x = -410; # The text/bitmap will be displayed starting from (not centered around) the left_x value # (unlike the case with a simple x value, in which case it will be centered around it ). top_y = 90; # Adapt the values as necessary to correspond to the text displayed in P_Selfpaced_Visual_Stimulus below. } P_Focus_Star; # Screen definition for showing the smileys for Acceptability Judgement picture { bitmap { filename = "Smiley_L.bmp"; }; # Use Smiley_L.bmp x = 0; y = 0; } P_Acceptability; # Screen definition for the End_Thanks trial picture { text {caption = "Das war's! Vielen Dank!";}; x = 0; y = 0; line_graphic Lin_Border; x = 0; y = 0; } P_End_Thanks; #### Specific for presenting Visual Stimuli -------------------------------- # Screen definition for the trial that presents Visual Stimuli word-by-word. picture { text { caption = " "; text_align = align_left; max_text_width = 1100; # This parameter works only in Presentation Version 16.4 or later versions. # Very useful parameter indeed. (Especially to recompose sentences, without having to # bother about inserting \n after every n words, and not worrying if the words/lines would be too long etc.) } Txt_Selfpaced_Visual_Stimulus; #x = 0; #y = 0; left_x = -395; # The text/bitmap will be displayed starting from (not centered around) the left_x value # (unlike the case with a simple x value, in which case it will be centered around it ). top_y = 100; } P_Selfpaced_Visual_Stimulus; #### #### Specific for presenting Probe Task from Textfile --------- # Screen definition for Probe Task (text), which includes dimmed blanks in place of the visual stimuli picture { text { caption = " "; text_align = align_left; max_text_width = 1100; # This parameter works only in Presentation Version 16.4 or later versions. # Very useful parameter indeed. (Especially to recompose sentences, without having to # bother about inserting \n after every n words, and not worrying if the words/lines would be too long etc.) font_color = "000, 102, 153, 153"; # The 4th value is the alpha value. 255 -> fully opaque; 0 -> fully transparent...almost invisible. } Txt_Blanks; #x = 0; #y = 0; left_x = -395; # The text/bitmap will be displayed starting from (not centered around) the left_x value # (unlike the case with a simple x value, in which case it will be centered around it ). top_y = 100; text {caption = " "; font_color = "220,30,0";} Txt_Probe; # PCL Program fills the caption. x = 0; y = -200; } P_Probe; ##### #===================== # Trial Definitions: - #===================== /**** /# Note that the name 'Trial' could be misleading. Unless otherwise specified, /# what we mean by a 'Trial' here is actually a sub-trial or sub-task that is /# part - and thereby defines the structure - of an actual experimental trial. ****/ /**** /# Template for defining an SDL Trial. /# trial /# { /# Trial-related parameters such as trial_duration, trial_type etc. /# Trial-related parameters /# /# Stimulus event 1 such as picture, sound, video, nothing or force-FB; /# Stimulus event parameters such as time, event code etc. /# If the parameters aren't specified, the default values are used!!! /# /# Stimulus event 2; /# its parameters...and so on /# } ****/ # Screen definition of the Trial to show a Blank Screen between Experimental Trials trial { trial_duration = 1000; all_responses = false; stimulus_event { picture {}; # This is the default picture, which is nothing! #code = "CLS"; # Comment this out to avoid seeing this in the logfile. } E_Blank_Screen; } T_Blank_Screen; # Definition of the Trial to start an Experimental Session. # Operator Controlled! trial { trial_duration = forever; # Keep running the trial... trial_type = specific_response; # ...until the following specific response. terminator_button = 3; # Operator PC - ENTER key. stimulus_event { picture P_Start_Exp; # Show P_Start_Exp. code = "The Experiment starts now!"; }; } T_Start_Exp; # Definition of the Trial to continue further. # Participant Controlled! trial { trial_duration = forever; # Keep running the trial... trial_type = specific_response; # ...until the following specific response. terminator_button = 1,2; # Participant Joystick - L or R button. stimulus_event { picture P_Continue; # Show P_Continue. code = "Trials follow!"; }; } T_Continue; # Definition of the Trial to Launch an Experimental Trial trial { trial_duration = 500; # Run the trial for 400 ms... all_responses = false; # ..without recognising any key presses. stimulus_event { picture P_Focus_Star; # Show the focus star for fixation. code = ""; # Code set below in the PCL program. # port_code = ; # Port code set by the PCL program. } E_Launch_New_Trial; } T_Launch_New_Trial; #### Specific for presenting Visual Stimuli -------------------------------- # Definition of the Trial to present Visual Stimuli word-by-word in a SELFPACED manner. trial { trial_duration = forever; # PCL Program changes this!!! trial_type = specific_response; terminator_button = 4; stimulus_event { picture P_Selfpaced_Visual_Stimulus; code = ""; # PCL Program fills this!!! # port_code = ; # PCL Program fills this!!! } E_Selfpaced_Visual_Stimulus; } T_Selfpaced_Visual_Stimulus; #### # Definition of the Trial to show Smileys for Acceptability Judgement. trial { trial_duration = 2000; trial_type = specific_response; terminator_button = 1,2; # The exact response can be either of these; stimulus_event { picture P_Acceptability; code = "191"; # PCL Program sets this. port_code = 191; # Send '191' to EEG target_button = 2; # 2 is good, 1 is bad; as always! } E_Acceptability; } T_Acceptability; # Definition of the Trial to show the Probe Task trial { trial_duration = forever; trial_type = specific_response; terminator_button = 1,2; # The exact response can be either of these; stimulus_event { picture P_Probe; code = "195"; # PCL Program sets this. port_code = 195; # Send '195' to EEG # target_button = 1,2; # PCL Program sets this. } E_Probe; } T_Probe; # Definition of the Trial to send a code indicating that a Timeout has occurred. /*# When a button-pressed response occurs, 1 or 2 is sent to EEG depending upon the button pressed. # When a timeout occurs, nothing gets sent. Just in order to have equal number of lines in the # trigger files later, it's better to send a code indicating timeout. # (Yes, IN ADDITION to the usual code 199 that will follow.) */ trial { trial_duration = 10; all_responses = false; stimulus_event { nothing {}; # This is the default picture, which is nothing! code = "Timeout"; port_code = 3; } E_Report_Timeout_to_EEG; } T_Report_Timeout_to_EEG; # Definition of the Trial to send the response code to EEG trial { trial_duration = 20; all_responses = false; stimulus_event { nothing {}; # Basically, nothing is done! time = 15; /*# Start this event 15 seconds after the trial starts. This is to provide a delay in # sending the code to EEG to avoid trying to reach the port when it is still busy # having just received the response 1 or 2 from the button box, or the timeout code. */ # code = "Send Code"; # Comment this out to avoid seeing this in the logfile. # port_code = 192, 193, 196, 197 or 199, PCL Program fills this!!! } E_Response_Code_to_EEG; } T_Response_Code_to_EEG; # Definition of the Trial to show a Pause # Operator Controlled trial { trial_duration = forever; trial_type = specific_response; terminator_button = 3; stimulus_event { picture P_Pause; code = "Pause"; }; } T_Pause; # Definition of the Trial to end the session # Operator Controlled trial { trial_duration = forever; all_responses = false; trial_type = first_response; stimulus_event { picture P_End_Thanks; code = "End of Session!"; }; picture P_End_Thanks; } T_End_Thanks; ############################################################################## # Presentation Control Language (PCL) Program Part ############################################################################## begin_pcl; #========================= # PCL Global Variables : - #========================= int N_of_Trials = 64; # Number of Experimental Trials per Session. int N_of_Blocks = 2; # Number of Blocks per Session. int N_of_Trials_per_Block = N_of_Trials/N_of_Blocks; # Number of Experimental Trials per Block. preset string V_Version; # Prompt the version at the beginning!!! input_file F_Session_List = new input_file; F_Session_List.open("Session_List_" + V_Version + ".txt"); # This is the file containing the list of stimuli for one session. # Each line in this file must correspond to one experimental trial. #### Specific for presenting Visual Stimuli -------------------------------- input_file F_Visual_Stimulus = new input_file; F_Visual_Stimulus.open("Visual_Stimulus_List_" + V_Version + ".txt"); string V_Strophe; string V_Strophe_Blanks; string V_Selfpaced_Visual_Stimulus; array<string> A_Stimulus_Words[0]; array<string> A_Selfpaced_Visual_Stimulus[0]; #### Specific for presenting Visual Stimuli + Text Comprehension Question --- int V_Current_Word; int V_Underscore_Index; int V_Star_Index; int V_Plus_Index; int V_Char_Index; int V_Newline_Index; int V_Line_Number; int V_Word_Number; int V_Current_Letter; int V_Current_Selfpaced_Stimulus; string V_Temp_Store_Restore_Blanks; int V_Counter; #### Specific for presenting Probe Task from Textfile --------- #input_file F_Probe = new input_file; #F_Probe.open("Probe_List_" + V_Version + ".txt"); #### # Columns of strings in the order found in the input Session List file. string V_Strophe_ID; string V_Item; string V_Condition; string V_Probe_Type; string V_Expected_Response; string V_Probe; # The probe word itself string V_Temp_Blanks; # output_port O_Port_to_EEG = output_port_manager.get_port(1); stimulus_data D_Stimulus_Data = stimulus_manager.last_stimulus_data(); #========================== # Subroutine Definitions: - #========================== sub Q_Execute_Probe_Task begin Txt_Blanks.set_caption(V_Strophe_Blanks.trim()); # Since we read the first word from Visual_Stimulus_List and then read the rest of the line, # the leading space is still present. This is trimmed in the main stimulus presentation # because we split the input into an array with space as the delimiter. # But here, it needs to be explicitly trimmed before presenting. Txt_Blanks.redraw(); Txt_Probe.set_caption(V_Probe); Txt_Probe.redraw(); E_Probe.set_event_code(V_Probe_Type); T_Probe.present(); # Monitor the Response and send appropriate port codes to EEG!!! D_Stimulus_Data = stimulus_manager.last_stimulus_data(); # To delay sending the following codes to the Output Port!!! # Because these are almost at the same time as the Response there, so the port # cannot handle it unless there's a short delay. if (D_Stimulus_Data.type() == stimulus_hit) then E_Response_Code_to_EEG.set_port_code(196); E_Response_Code_to_EEG.set_event_code("Correct"); T_Response_Code_to_EEG.present(); elseif (D_Stimulus_Data.type() == stimulus_incorrect) then E_Response_Code_to_EEG.set_port_code(197); E_Response_Code_to_EEG.set_event_code("Incorrect"); T_Response_Code_to_EEG.present(); elseif (D_Stimulus_Data.type() == stimulus_miss) then T_Report_Timeout_to_EEG.present(); E_Response_Code_to_EEG.set_port_code(199); E_Response_Code_to_EEG.set_event_code("TimeoutP"); T_Response_Code_to_EEG.present(); end; end; #======================== # Main Experiment Loop: - #======================== loop /*** Begin Main Loop 1 for Blocks ***/ int V_Current_Block = 1 until V_Current_Block > N_of_Blocks begin if V_Current_Block == 1 then T_Start_Exp.present(); T_Continue.present(); else T_Pause.present(); T_Continue.present(); end; T_Blank_Screen.present(); #========== # Loop 2: - #========== loop /*** Begin Loop 2 for Trials ***/ int V_Current_Trial = 1 until V_Current_Trial > N_of_Trials_per_Block begin V_Strophe_ID = F_Session_List.get_string(); # Eg: 01POL V_Item = F_Session_List.get_string(); # Eg: 01 V_Condition = F_Session_List.get_string(); # Eg: POL V_Probe_Type = F_Session_List.get_string(); V_Expected_Response = F_Session_List.get_string(); # Eg: 2 (Left button => Correct) V_Probe = F_Session_List.get_string(); # Eg: Sommerpracht ### Example lines from Session_List for Polione ### 01POL 01 POL 140 2 Probe-triggerword Probe # 01POL 01 POL 140 2 Sommernacht Sommerpracht # 02POL 02 POL 150 1 moves stays # Do filename and event-code assignments valid during this exp-trial; # Load wavefile and bitmap stimuli that are needed for this trial; # We do this before launching the experimental trial so as to keep # as minimal intereference as possible in trial timings. You see, # these things consume processor time, however small they are! E_Launch_New_Trial.set_event_code("B" + string(V_Current_Block) + "_T" + string(V_Current_Trial)); E_Probe.set_target_button(int(V_Expected_Response)); # Execute the Experimental Trial!!! # Dirty hard-coded solution for the 08-09 Presentation Bug!!! if (V_Item == "08") then V_Item = "8"; elseif (V_Item == "09") then V_Item = "9"; end; E_Launch_New_Trial.set_port_code(int(V_Item)); T_Launch_New_Trial.present(); # Show Star for 400 ms /***************** Visual Stimulus Presentation Begins ***********************/ T_Blank_Screen.set_duration(100); # This duration will be the inter-word interval. See below. T_Blank_Screen.present(); #A_Stimulus_Lines.resize(0); A_Stimulus_Words.resize(0); # Empty the arrays. A_Selfpaced_Visual_Stimulus.resize(0); V_Line_Number = 1; V_Word_Number = 1; V_Strophe_ID = F_Visual_Stimulus.get_string(); # Read the first string...it is the index. V_Strophe = F_Visual_Stimulus.get_line(); # Read the rest of the line at a time from the file. # This includes the space in the beginning. V_Strophe_Blanks = V_Strophe; # Replace text with corresponding blanks in V_Strophe_Blanks loop V_Current_Letter = 1 until V_Current_Letter > V_Strophe.count() begin if (V_Strophe.substring(V_Current_Letter,1) != " " && V_Strophe.substring(V_Current_Letter,1) != "_" && V_Strophe.substring(V_Current_Letter,1) != "+") then V_Strophe_Blanks.set_char(V_Current_Letter, 45); # 45 -> "-" / 95 -> "_" end; V_Current_Letter = V_Current_Letter + 1; end; # A + in the input => new line. # Find if there's a + in the current stimulus. # If there's one, replace it with a Line-Feed character (ASCII Char decimal 10) before presenting the words. loop V_Counter = 1 until V_Counter > 5 begin V_Plus_Index = 0; V_Plus_Index = V_Strophe.find("+"); if V_Plus_Index != 0 then V_Strophe.set_char(V_Plus_Index, 10); # Decimal 10 => Line-Feed character (Nicht das CR (13) benutzen!!!) V_Strophe_Blanks.set_char(V_Plus_Index, 10); end; V_Counter = V_Counter + 1; end; # Empty all the strings that will be used further below. V_Selfpaced_Visual_Stimulus = ""; # Split the stimulus sentence strophe word by word, and store the words in an array. # If two words need to be together, there must be an _ in the input! V_Strophe.split(" ",A_Stimulus_Words); # Split the blank sentence similarly, and store the blank words in another array. V_Strophe_Blanks.split(" ",A_Selfpaced_Visual_Stimulus); # In both the above arrays, the first array element is the Condition Code from the Stimulus List, if we are dealing with the first strophe. # We will take care not to display that (see below). # #============ # Loop 2.1: - #============ loop /*** Begin Loop 2.2 for Presenting Stimulus Words with Blanks ***/ V_Current_Selfpaced_Stimulus = 1 until V_Current_Selfpaced_Stimulus > A_Stimulus_Words.count() begin V_Temp_Store_Restore_Blanks = A_Selfpaced_Visual_Stimulus[V_Current_Selfpaced_Stimulus]; A_Selfpaced_Visual_Stimulus[V_Current_Selfpaced_Stimulus] = A_Stimulus_Words[V_Current_Selfpaced_Stimulus]; # We need some sensible entries in the logfile, such as line number and word number in a given line. # The first time, we just disply blanks, so just the Item number will be the logfile entry. # From the second time on, we are displaying one word at a time. # To reflect this, we increment a Word_Number. if V_Current_Selfpaced_Stimulus != 1 then E_Selfpaced_Visual_Stimulus.set_event_code("L" + string(V_Line_Number) + "_W" + string(V_Word_Number)); V_Word_Number = V_Word_Number + 1; else E_Selfpaced_Visual_Stimulus.set_event_code("Item_" + V_Item); end; # If the next word is not the last word # Then check if it has an 'Enter' character in front of it. # If it does, it means that we are going to the next line. # Increment the line counter accordingly; Reset the word counter. if V_Current_Selfpaced_Stimulus+1 < A_Stimulus_Words.count() then V_Newline_Index = A_Stimulus_Words[V_Current_Selfpaced_Stimulus+1].find("\n"); if V_Newline_Index != 0 then # We are on the last word of a given line (not the last line) # Overwrite the Event Code we assigned above, to indicate that this is a rhyme (=critical) word. E_Selfpaced_Visual_Stimulus.set_event_code("L" + string(V_Line_Number) + "_RHYME"); V_Line_Number = V_Line_Number + 1; V_Word_Number = 1; end; V_Newline_Index = 0; end; ##### Polione_Post: Probe Task follows the last word always (as usual...see below). # #============ # Loop 2.1.1: - #============ loop # Construct the self-paced stimulus V_Current_Word = 1 until V_Current_Word > A_Selfpaced_Visual_Stimulus.count() begin #E_Selfpaced_Visual_Stimulus.set_event_code("L" + string(V_Line_Number) + "W" + string(V_Word_Number)); if (V_Current_Word == 1) then # Leave the first one out, because that's the Stimulus Number or Index or so, but only for the first ever strophe. #V_Selfpaced_Visual_Stimulus = V_Selfpaced_Visual_Stimulus; # Just nothing, or, if some star or something is necessary, that can be included here. V_Selfpaced_Visual_Stimulus = V_Selfpaced_Visual_Stimulus + A_Selfpaced_Visual_Stimulus[V_Current_Word]; elseif (V_Current_Word != A_Selfpaced_Visual_Stimulus.count()) then V_Selfpaced_Visual_Stimulus = V_Selfpaced_Visual_Stimulus + A_Selfpaced_Visual_Stimulus[V_Current_Word] + " "; else V_Selfpaced_Visual_Stimulus = V_Selfpaced_Visual_Stimulus + A_Selfpaced_Visual_Stimulus[V_Current_Word]; end; V_Current_Word = V_Current_Word + 1; #=============== # End Loop 2.1.1 #=============== end; # Loop 2.1.1 ends A_Selfpaced_Visual_Stimulus[V_Current_Selfpaced_Stimulus] = V_Temp_Store_Restore_Blanks; # Send triggers for each word. #E_Selfpaced_Visual_Stimulus.set_event_code(V_Condition_Code); # Find if there's an underscore in the current stimulus. # If there's one, replace it with a space (ASCII Char 32) before presenting the words. # An underscore means that the words need to be presented together, as in 'Of course'! # For now, we'll run the loop 5 times, meaning we can replace up to 5 underscores here. loop V_Counter = 1 until V_Counter > 5 begin V_Underscore_Index = 0; V_Underscore_Index = V_Selfpaced_Visual_Stimulus.find("_"); if V_Underscore_Index != 0 then V_Selfpaced_Visual_Stimulus.set_char(V_Underscore_Index, 32); end; V_Counter = V_Counter + 1; end; Txt_Selfpaced_Visual_Stimulus.set_caption(V_Selfpaced_Visual_Stimulus); Txt_Selfpaced_Visual_Stimulus.redraw(); T_Selfpaced_Visual_Stimulus.present(); # Reset things before going to the next word! V_Selfpaced_Visual_Stimulus = ""; E_Selfpaced_Visual_Stimulus.set_event_code(""); # Go to the next word. V_Current_Selfpaced_Stimulus = V_Current_Selfpaced_Stimulus + 1; #============= # End Loop 2.1 #============= end; /*** End Loop 2.1 for Presenting Stimulus Words with Blanks ***/ /***************** Visual Stimulus Presentation Ends *************************/ ##### Polione_Post: Probe Task follows the last word always (as usual). Q_Execute_Probe_Task(); # Reset Duration for the Blank Screen T_Blank_Screen.set_duration(1000); T_Blank_Screen.present(); # Go to the Next Trial V_Current_Trial = V_Current_Trial + 1; #=========== # End Loop 2 #=========== end; /*** End Loop 2 for Trials ***/ # Go to the Next Block V_Current_Block = V_Current_Block + 1; #================ # End Main Loop 1 #================ end; /*** End Main Loop 1 for Blocks ***/ # Close all the open files F_Session_List.close(); F_Visual_Stimulus.close(); #F_Probe.close(); # Finish off the session!!! T_End_Thanks.present(); #=========================================================================================================