Back to MATLAB Programming/Psychtoolbox
function output = xsearch3()
% generic visual search architecture
% started 12/06/2005
% current 12/06/2005
% Todd S. Horowitz
global screenRect MainWindow
% this bit should make the code windows/macos9 portable
if strcmp(computer, 'PCWIN')
warning off MATLAB:DeprecatedLogicalAPI;
end
% get parameter input (optional)
prompt = {'subject''s initials', 'practice trials', 'experimental trials', 'set sizes'};
defaults = {'xxx', '5', '50', '[4 8 16]'};
answer = inputdlg(prompt, 'Experimental Setup Information', 1, defaults);
% now decode answer
[subject, pTrials, xTrials, setsizes] = deal(answer{:});
pTrials = str2num(pTrials);
xTrials = str2num(xTrials);
setsizes = str2num(setsizes);
% other major variables
formatString = '%s, %d, %d, %d, %d, %d, %d, %d, %d \n'; % this is for data output
% saved variables: subject, block, trial, target, setSize, timeoutFlag, wrongKeyFlag, err, RT
keys = [KbName('''') KbName('a')]; % response key assignments
dataFileName = 'xsearch3Data';
jitter = 10; % coordinates of stimuli will vary by up to this much in their grid cells
if exist(dataFileName, 'file') == 0
dataFile = fopen(dataFileName, 'a');
count = fprintf(dataFile, '%s \n', 'subject, block, trial, target, setSize, timeoutFlag, wrongKeyFlag, err, RT');
fclose('all');
end
% set the state of the random number generator to some random value (based on the clock)
tau = clock;
rand('state',sum(100*tau));
state=rand('state');
seedFileName = ['pptxSeed-', subject];
save (seedFileName, 'tau');
% basic setup stuff
screens = Screen('Screens');
MainScreen = max(screens);
% video setup
% this sets up a display which is the size of the current monitor
% the color is 8 bits, the lowest color resolution, this is for speed and compactness
% if you're using images, you might want to change bitDepth to 32
% on MacOS9, you can also specify a screenRect smaller than the actual monitor
bitDepth = 8;
MainWindow = screen(0, 'OpenWindow', [], [], bitDepth);
hz = round(screen(MainWindow, 'FrameRate'))
HideCursor;
% define rects
screenRect = screen(0, 'Rect');
objectSize=40;
objectRect = [0 0 objectSize objectSize]; % this is the size of the individual items
stimulusRect = [0 0 500 500]; % this is an area smaller than the full screen in which to present stimuli
fieldRect = CenterRect(stimulusRect, screenRect);
% define coordinate system
cellX = 100; cellY = cellX; % these are the cells of the imaginary stimulus matrix
nColumns = 5;
nRows = 5;
columns = ((1:nColumns) - .5) * cellX;
rows = ((1:nRows) - .5) * cellY;
[X, Y] = meshgrid(columns, rows); % this is the coordinate system for the stimuli, relative to stimulusRect
nPositions = nColumns * nRows;
nSetSizes = length(setsizes);
maxWait = 5; % allow 5 seconds for response
fixationDuration = 30; % this is in refreshes
% now set colors
dacBits = ScreenDacBits(MainWindow);
white = WhiteIndex(MainWindow);
black = BlackIndex(MainWindow);
midGray = round((white+black)/2);
if round(midGray)==white
midGray=black;
end
darkGray = (midGray+black)/2;
lightGray = (midGray+white)/2;
red = 1;
blue = 2;
green = 3;
clut = screen(MainWindow, 'GetClut');
clut (red + 1, :) = [255 0 0];
clut (blue + 1, :) = [0 0 255];
clut (green + 1, :) = [0 255 0];
if dacBits == 10
clut = clut*1024/256;
end
LoadClut(MainWindow, clut);
screen(MainWindow, 'FillRect', midGray);
screen(MainWindow, 'TextFont', 'Skia');
screen(MainWindow, 'TextSize', 24);
% more offscreen windows
backgroundColor = midGray;
stimulus = screen(MainWindow, 'OpenOffscreenWindow', midGray, stimulusRect);
% make stimuli
% here I'm drawing the stimuli, but one can also use alphanumeric characters or import jpegs
itemColor = black;
stroke = 10;
topRect = [0 0 objectSize stroke];
bottomRect = [0 objectSize - stroke objectSize, objectSize];
hCrossRect = [0 (objectSize - stroke)/2 objectSize (objectSize + stroke)/2];
vCrossRect = [(objectSize - stroke)/2 0 (objectSize + stroke)/2 objectSize];
leftRect = [0 0 stroke, objectSize];
rightRect = [objectSize - stroke 0 objectSize objectSize];
t(1) = screen(MainWindow, 'OpenOffscreenWindow', backgroundColor, objectRect);
screen(t(1), 'FillRect', itemColor, topRect);
screen(t(1), 'FillRect', itemColor, vCrossRect);
t(2) = screen(MainWindow, 'OpenOffscreenWindow', backgroundColor, objectRect);
screen(t(2), 'FillRect', itemColor, rightRect);
screen(t(2), 'FillRect', itemColor, hCrossRect);
t(3) = screen(MainWindow, 'OpenOffscreenWindow', backgroundColor, objectRect);
screen(t(3), 'FillRect', itemColor, bottomRect);
screen(t(3), 'FillRect', itemColor, vCrossRect);
t(4) = screen(MainWindow, 'OpenOffscreenWindow', backgroundColor, objectRect);
screen(t(4), 'FillRect', itemColor, leftRect);
screen(t(4), 'FillRect', itemColor, hCrossRect);
d(1) = screen(MainWindow, 'OpenOffscreenWindow', backgroundColor, objectRect);
screen(d(1), 'FillRect', itemColor, leftRect);
screen(d(1), 'FillRect', itemColor, bottomRect);
d(2) = screen(MainWindow, 'OpenOffscreenWindow', backgroundColor, objectRect);
screen(d(2), 'FillRect', itemColor, leftRect);
screen(d(2), 'FillRect', itemColor, topRect);
d(3) = screen(MainWindow, 'OpenOffscreenWindow', backgroundColor, objectRect);
screen(d(3), 'FillRect', itemColor, rightRect);
screen(d(3), 'FillRect', itemColor, topRect);
d(4) = screen(MainWindow, 'OpenOffscreenWindow', backgroundColor, objectRect);
screen(d(4), 'FillRect', itemColor, rightRect);
screen(d(4), 'FillRect', itemColor, bottomRect);
fixation = screen(MainWindow, 'OpenOffscreenWindow', backgroundColor, objectRect);
screen(fixation, 'FillRect', itemColor, vCrossRect);
screen(fixation, 'FillRect', itemColor, hCrossRect);
fixationRect = CenterRect(objectRect,screenRect);
screen(MainWindow, 'FillRect', backgroundColor); % this blanks the screen
instructionString = {
'Your task is to look for a T in the display';
'If you see a T, press the "quote" key with your right hand.'
'If you are sure that there is no T in the display, press the "a" key with your left hand.';
'Please respond as quickly and accurately as possible.';
['There will be ', num2str(pTrials), ' practice trials followed by ', num2str(xTrials), ' experimental trials.'];
};
CenterCellText(MainWindow, instructionString);
SitnWait;
% block routine
for block = 1:2
if block == 1
blockMessage = 'Practice ';
nTrials = pTrials;
else
blockMessage = 'Experimental ';
nTrials = xTrials;
end
nTrialString = num2str(nTrials);
screen(MainWindow, 'FillRect', midGray);
message = [' Press any key to begin ', nTrialString, ' ', blockMessage, 'trials'];
CenterText(message);
SitnWait;
% trial routine
for trial = 1:nTrials
screen(MainWindow, 'FillRect', backgroundColor); %start with a blank screen
screen(stimulus, 'FillRect', backgroundColor); %start with a blank screen
% now select trial properties
target = randi(2); % 1 = target present, 2 = target absent
setSize = setsizes(randi(nSetSizes));
positionIndex = randperm(nPositions); % randomize order of stimulus placement
selectItem = mod(randperm(setSize ) - 1, 4) + 1; % this ensures that distractor types will be distributed evenly
% put stimuli onto stimulus screen
for i = 1:setSize
if target == 1 & i == 1
item = t(selectItem(1));
else
item = d(selectItem(i));
end
dx = round(randi(jitter) - jitter/2);
dy = round(randi(jitter) - jitter/2);
itemRect = CenterRectOnPoint(objectRect, X(positionIndex(i)) + dx, Y(positionIndex(i)) + dy);
screen('CopyWindow', item, stimulus, objectRect, itemRect);
end
% present fixation cross
screen('CopyWindow', fixation, MainWindow, objectRect, fixationRect);
screen(MainWindow, 'WaitBlanking', fixationDuration); % synch to the vertical refresh for fixationDuration refreshes
% now copy display to screen in one fell swoop
screen('CopyWindow', stimulus, MainWindow, stimulusRect, fieldRect);
% now wait for a response
initTime = GetSecs;
response = [];
while isempty(response)&(GetSecs - initTime) < maxWait
[keyIsDown, KbTime, keyCode] = KbCheck;
if keyIsDown
response = find(keyCode);
response = response(1);
responseTime = KbTime;
end
end
if isempty(response)
timeoutFlag = 1;
err = 1;
feedback = 'Time out!';
RT = 0;
else
timeoutFlag = 0;
responseKey = find(keys == response);
wrongKeyFlag = 0;
RT = round((responseTime - initTime) * 1000); % RT in ms
if isempty(responseKey)
err = 1;
feedback = 'Wrong Key! Use "a" for "no" and "quote" for "yes"!';
wrongKeyFlag = 1;
elseif responseKey == target
err = 0;
feedback = 'Correct!';
else
err = 1;
feedback = 'Wrong!';
end
end
% save trial data
% note that you should open and close the file every time you write to it, otherwise you may lose data in crashes
dataFile = fopen(dataFileName, 'a');
fprintf(dataFile, formatString, subject, block, trial, target, setSize, timeoutFlag, wrongKeyFlag, err, RT);
fclose(dataFile);
screen(MainWindow, 'FillRect', midGray);
CenterText([feedback, ' - RT = ', num2str(RT), ' ms']);
WaitSecs(1);
end % trial loop
end % block loop
% clean up and go home
screen(MainWindow, 'FillRect', midGray);
CenterText('Thank you for participating');
SitnWait;
clear screen;
function SitnWait()
FlushEvents('keyDown');
GetChar;
function CenterText (message, xoffset, yoffset, color, window)
% print a text string centered on the screen
% syntax [newX, newY] = CenterText (message, [xoffset], [yoffset], [color], [window])
% if you want the text offset from center, use xoffset and yoffset
% if window is not specified, prints to MainWindow, which must be a global in the calling function
% 2/23/2000 accepts color option
% 4/23/2002 can now print to offscreen windows
global screenX
global screenY
global MainWindow
switch nargin
case 1
xoffset=0;
yoffset=0;
color = [];
window = MainWindow;
case 2
yoffset=0;
color = [];
window = MainWindow;
case 3
color = [];
window = MainWindow;
case 4
window = MainWindow;
end
windowRect = screen(window, 'Rect');
width = screen(window, 'TextWidth', message);
screen(window, 'DrawText', message, ((windowRect(3)/2)-(width/2))+xoffset, (windowRect(4)/2)+yoffset, color);
function CenterCellText(window, messages, spacing, color)
% prints a cell array of text strings centered on the screen
% syntax [newX, newY] = CenterCellText(window, messages, [spacing], [color])
% messages is a cell array of lines of text
% spacing governs the distance between lines of text, in pixels
% default spacing is 20 pixels
% added color option 1/17/2003; only does one color for the whole thing
% fixed number of options bug 01/24/2003
defaultSpacing = 30;
switch nargin
case 0
error('CenterCellText requires at least two arguments!');
case 1
error('CenterCellText requires at least two arguments!');
case 2
spacing = defaultSpacing;
color = [];
case 3
color = [];
end
lines = length (messages);
% find the middle line
middleLine = round(lines/2);
yOffset = spacing*((1:lines)-middleLine);
for y = 1:lines
CenterText(messages{y}, 0, yOffset(y), color, window);
end