MATLAB Programming/Psychtoolbox/Example Code/xsearch

From Wikibooks, open books for an open world
< MATLAB Programming‎ | Psychtoolbox‎ | Example Code
Jump to: navigation, search
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