|
| 1 | +%% Auditory hMT localizer using translational motion in four directions |
| 2 | +% (up- down- left and right-ward) |
| 3 | + |
| 4 | +% Original Script Written by Sam Weiller to localize MT+/V5 |
| 5 | +% adapted by M.Rezk to localize MT/MST (Huk,2002) |
| 6 | +% re-adapted by MarcoB and RemiG 2020 |
| 7 | + |
| 8 | +%% |
| 9 | + |
| 10 | +% Clear all the previous stuff |
| 11 | +% clc; clear; |
| 12 | +if ~ismac |
| 13 | + close all; |
| 14 | + clear Screen; |
| 15 | +end |
| 16 | + |
| 17 | +% make sure we got access to all the required functions and inputs |
| 18 | +addpath(genpath(fullfile(pwd, 'subfun'))) |
| 19 | + |
| 20 | +[expParameters, cfg] = setParameters; |
| 21 | + |
| 22 | +% set and load all the parameters to run the experiment |
| 23 | +expParameters = userInputs(cfg, expParameters); |
| 24 | + |
| 25 | +expParameters = createFilename(cfg, expParameters); |
| 26 | + |
| 27 | +expParameters %#ok<NOPTS> |
| 28 | + |
| 29 | +%% Experiment |
| 30 | + |
| 31 | +% Safety loop: close the screen if code crashes |
| 32 | +try |
| 33 | + |
| 34 | + %% Init the experiment |
| 35 | + [cfg] = initPTB(cfg); |
| 36 | + |
| 37 | + % % Convert some values from degrees to pixels |
| 38 | + % cfg = deg2Pix('diameterAperture', cfg, cfg); |
| 39 | + % expParameters = deg2Pix('dotSize', expParameters, cfg); |
| 40 | + |
| 41 | + |
| 42 | + [el] = eyeTracker('Calibration', cfg, expParameters); |
| 43 | + |
| 44 | + % % % REFACTOR THIS FUNCTION |
| 45 | + [expParameters] = expDesign(expParameters); |
| 46 | + % % % |
| 47 | + |
| 48 | + % Prepare for the output logfiles with all |
| 49 | + logFile = saveEventsFile('open', expParameters, [], ... |
| 50 | + 'direction', 'speed', 'target', 'event', 'block'); |
| 51 | + |
| 52 | + logFile |
| 53 | + |
| 54 | + % % % REFACTOR THIS FUNCTION |
| 55 | + [expParameters] = loadAudioFiles(cfg, expParameters); |
| 56 | + phandle = PsychPortAudio('Open',[],[],1,expParameters.freq,2); |
| 57 | + % % % |
| 58 | + |
| 59 | + % Prepare for fixation Cross |
| 60 | + if expParameters.Task1 |
| 61 | + |
| 62 | + cfg.xCoords = [-expParameters.fixCrossDimPix expParameters.fixCrossDimPix 0 0] ... |
| 63 | + + expParameters.xDisplacementFixCross; |
| 64 | + |
| 65 | + cfg.yCoords = [0 0 -expParameters.fixCrossDimPix expParameters.fixCrossDimPix] ... |
| 66 | + + expParameters.yDisplacementFixCross; |
| 67 | + |
| 68 | + cfg.allCoords = [cfg.xCoords; cfg.yCoords]; |
| 69 | + |
| 70 | + end |
| 71 | + |
| 72 | + % Wait for space key to be pressed |
| 73 | + pressSpace4me |
| 74 | + |
| 75 | + % prepare the KbQueue to collect responses |
| 76 | + getResponse('init', cfg, expParameters, 1); |
| 77 | + getResponse('start', cfg, expParameters, 1); |
| 78 | + |
| 79 | + % Show instructions |
| 80 | + if expParameters.Task1 |
| 81 | + DrawFormattedText(cfg.win,expParameters.TaskInstruction,... |
| 82 | + 'center', 'center', cfg.textColor); |
| 83 | + Screen('Flip', cfg.win); |
| 84 | + end |
| 85 | + |
| 86 | + % Wait for Trigger from Scanner |
| 87 | + wait4Trigger(cfg) |
| 88 | + |
| 89 | + % Show the fixation cross |
| 90 | + if expParameters.Task1 |
| 91 | + drawFixationCross(cfg, expParameters, expParameters.fixationCrossColor) |
| 92 | + Screen('Flip',cfg.win); |
| 93 | + end |
| 94 | + |
| 95 | + %% Experiment Start |
| 96 | + cfg.experimentStart = GetSecs; |
| 97 | + |
| 98 | + WaitSecs(expParameters.onsetDelay); |
| 99 | + |
| 100 | + %% For Each Block |
| 101 | + |
| 102 | + stopEverything = 0; |
| 103 | + |
| 104 | + for iBlock = 1:expParameters.numBlocks |
| 105 | + |
| 106 | + if stopEverything |
| 107 | + break; |
| 108 | + end |
| 109 | + |
| 110 | + fprintf('\n - Running Block %.0f \n',iBlock) |
| 111 | + |
| 112 | + eyeTracker('StartRecording', cfg, expParameters); |
| 113 | + |
| 114 | + % For each event in the block |
| 115 | + for iEvent = 1:expParameters.numEventsPerBlock |
| 116 | + |
| 117 | + |
| 118 | + % Check for experiment abortion from operator |
| 119 | + [keyIsDown, ~, keyCode] = KbCheck(cfg.keyboard); |
| 120 | + if keyIsDown && keyCode(KbName(cfg.escapeKey)) |
| 121 | + stopEverything = 1; |
| 122 | + warning('OK let us get out of here') |
| 123 | + break; |
| 124 | + end |
| 125 | + |
| 126 | + |
| 127 | + % set direction, speed of that event and if it is a target |
| 128 | + thisEvent.trial_type = 'dummy'; |
| 129 | + thisEvent.direction = expParameters.designDirections(iBlock,iEvent); |
| 130 | + thisEvent.speed = expParameters.designSpeeds(iBlock,iEvent); |
| 131 | + thisEvent.target = expParameters.designFixationTargets(iBlock,iEvent); |
| 132 | + |
| 133 | + % play the sounds and collect onset and duration of the event |
| 134 | + [onset, duration] = doAudMot(cfg, expParameters, thisEvent, phandle); |
| 135 | + |
| 136 | + thisEvent.event = iEvent; |
| 137 | + thisEvent.block = iBlock; |
| 138 | + thisEvent.duration = duration; |
| 139 | + thisEvent.onset = onset - cfg.experimentStart; |
| 140 | + |
| 141 | + % Save the events txt logfile |
| 142 | + % we save event by event so we clear this variable every loop |
| 143 | + thisEvent.fileID = logFile.fileID; |
| 144 | + |
| 145 | + saveEventsFile('save', expParameters, thisEvent, ... |
| 146 | + 'direction', 'speed', 'target', 'event', 'block'); |
| 147 | + |
| 148 | + clear thisEvent |
| 149 | + |
| 150 | + |
| 151 | + % collect the responses and appends to the event structure for |
| 152 | + % saving in the tsv file |
| 153 | + responseEvents = getResponse('check', cfg, expParameters); |
| 154 | + |
| 155 | + if ~isempty(responseEvents(1).onset) |
| 156 | + |
| 157 | + responseEvents.fileID = logFile.fileID; |
| 158 | + |
| 159 | + for iResp = 1:size(responseEvents, 1) |
| 160 | + responseEvents(iResp).onset = ... |
| 161 | + responseEvents(iResp).onset - cfg.experimentStart; |
| 162 | + responseEvents(iResp).target = expParameters.designFixationTargets(iBlock,iEvent); |
| 163 | + responseEvents(iResp).event = iEvent; |
| 164 | + responseEvents(iResp).block = iBlock; |
| 165 | + end |
| 166 | + |
| 167 | + saveEventsFile('save', expParameters, responseEvents, ... |
| 168 | + 'direction', 'speed', 'target', 'event', 'block'); |
| 169 | + end |
| 170 | + |
| 171 | + % wait for the inter-stimulus interval |
| 172 | + WaitSecs(expParameters.ISI); |
| 173 | + |
| 174 | + getResponse('flush', cfg, expParameters); |
| 175 | + |
| 176 | + end |
| 177 | + |
| 178 | + eyeTracker('StopRecordings', cfg, expParameters); |
| 179 | + |
| 180 | + WaitSecs(expParameters.IBI); |
| 181 | + |
| 182 | + end |
| 183 | + |
| 184 | + % End of the run for the BOLD to go down |
| 185 | + WaitSecs(expParameters.endDelay); |
| 186 | + |
| 187 | + % Close the logfiles |
| 188 | + saveEventsFile('close', expParameters, logFile); |
| 189 | + |
| 190 | + getResponse('stop', cfg, expParameters, 1); |
| 191 | + |
| 192 | + totalExperimentTime = GetSecs-cfg.experimentStart; |
| 193 | + |
| 194 | + eyeTracker('Shutdown', cfg, expParameters); |
| 195 | + |
| 196 | + % save the whole workspace |
| 197 | + matFile = fullfile(expParameters.outputDir, strrep(expParameters.fileName.events,'tsv', 'mat')); |
| 198 | + if IsOctave |
| 199 | + save(matFile, '-mat7-binary'); |
| 200 | + else |
| 201 | + save(matFile, '-v7.3'); |
| 202 | + end |
| 203 | + |
| 204 | + cleanUp() |
| 205 | + |
| 206 | +catch |
| 207 | + |
| 208 | + cleanUp() |
| 209 | + psychrethrow(psychlasterror); |
| 210 | + |
| 211 | +end |
0 commit comments