rmeddis@0
|
1 function errormsg=nextStimulus(handles)
|
rmeddis@0
|
2 % Handles everything concerned with the stimulus presentation
|
rmeddis@0
|
3 % called from startNewRun in subjGUI
|
rmeddis@0
|
4
|
rmeddis@38
|
5 global experiment stimulusParameters withinRuns betweenRuns
|
rmeddis@0
|
6 experiment.status='presentingStimulus';
|
rmeddis@0
|
7 errormsg='';
|
rmeddis@0
|
8
|
rmeddis@0
|
9 % interrupt by 'stop' button
|
rmeddis@29
|
10 % if experiment.stop
|
rmeddis@29
|
11 % disp('******** experiment manually stopped *****************')
|
rmeddis@29
|
12 % experiment.status= 'waitingForStart';
|
rmeddis@29
|
13 % errormsg='manually stopped';
|
rmeddis@29
|
14 % addToMsg(errormsg,1)
|
rmeddis@29
|
15 % return
|
rmeddis@29
|
16 % end
|
rmeddis@0
|
17
|
rmeddis@0
|
18 % -----------------------------------------choose catch trials at random
|
rmeddis@0
|
19 % catch trials are for subject threshold measurements only
|
rmeddis@0
|
20 % this is the only place where withinRuns.catchTrial is set
|
rmeddis@0
|
21 if experiment.allowCatchTrials
|
rmeddis@0
|
22 if withinRuns.trialNumber==1;
|
rmeddis@0
|
23 % first trial is never a catch trial
|
rmeddis@0
|
24 withinRuns.catchTrial=0;
|
rmeddis@0
|
25 withinRuns.catchTrialCount=0; % reset count on first trial
|
rmeddis@0
|
26 elseif withinRuns.trialNumber==2 ...
|
rmeddis@0
|
27 && withinRuns.catchTrialCount==0
|
rmeddis@0
|
28 % second trial is always a catch trial
|
rmeddis@0
|
29 withinRuns.catchTrial=1;
|
rmeddis@0
|
30 withinRuns.catchTrialCount=1; % this must be the first
|
rmeddis@0
|
31 elseif withinRuns.thisIsRepeatTrial
|
rmeddis@0
|
32 % for requested repeats do not change catch trial status
|
rmeddis@0
|
33 withinRuns.thisIsRepeatTrial=0; % reset toggle
|
rmeddis@0
|
34 else
|
rmeddis@0
|
35 % choose whether or not to have a catch trial
|
rmeddis@0
|
36 R=rand;
|
rmeddis@0
|
37 if R<stimulusParameters.catchTrialRate
|
rmeddis@0
|
38 % catch trial
|
rmeddis@0
|
39 withinRuns.catchTrial=1;
|
rmeddis@0
|
40 addToMsg('Catch Trial',1)
|
rmeddis@0
|
41 withinRuns.catchTrialCount=withinRuns.catchTrialCount+1;
|
rmeddis@0
|
42 else
|
rmeddis@0
|
43 % not a catch trial
|
rmeddis@0
|
44 withinRuns.catchTrial=0;
|
rmeddis@0
|
45 end
|
rmeddis@0
|
46 end
|
rmeddis@0
|
47 else
|
rmeddis@0
|
48 % no catch trials for statistical evaluations or 2AIFC or (poss) MAP
|
rmeddis@0
|
49 withinRuns.catchTrial=0;
|
rmeddis@0
|
50 end
|
rmeddis@0
|
51
|
rmeddis@0
|
52 %------------ during stimulus presentation show appropriate button images
|
rmeddis@0
|
53 switch experiment.ear
|
rmeddis@0
|
54 case {'statsModelLogistic', 'statsModelRareEvent',...
|
rmeddis@0
|
55 'MAPmodel', 'MAPmodelMultiCh', 'MAPmodelSingleCh'}
|
rmeddis@0
|
56 % no buttons shown
|
rmeddis@0
|
57 otherwise
|
rmeddis@0
|
58 switch experiment.threshEstMethod
|
rmeddis@0
|
59 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@0
|
60 %Except for 2I2AFC
|
rmeddis@0
|
61 % For 2I2AFC the buttons on the screen ab initio
|
rmeddis@0
|
62 set(handles.frame1,'visible','off')
|
rmeddis@0
|
63 set(handles.pushbuttonGO,'visible','off')
|
rmeddis@0
|
64 set(handles.pushbuttoNotSure,'visible','off')
|
rmeddis@0
|
65 set(handles.pushbuttonWrongButton,'visible','off')
|
rmeddis@0
|
66 set(handles.pushbutton3,'visible','off')
|
rmeddis@0
|
67 set(handles.pushbutton0,'visible','off')
|
rmeddis@0
|
68 set(handles.pushbutton1,'visible','on')
|
rmeddis@0
|
69 set(handles.pushbutton2,'visible','on')
|
rmeddis@0
|
70 drawnow
|
rmeddis@0
|
71 otherwise
|
rmeddis@0
|
72 % i.e. single interval/ maxLikelihood
|
rmeddis@0
|
73 set(handles.frame1,'backgroundColor','w')
|
rmeddis@0
|
74 set(handles.frame1,'visible','off')
|
rmeddis@0
|
75 set(handles.pushbuttoNotSure,'visible','off')
|
rmeddis@0
|
76 set(handles.pushbuttonWrongButton,'visible','off')
|
rmeddis@0
|
77 set(handles.pushbutton3,'visible','off')
|
rmeddis@0
|
78 set(handles.pushbutton2,'visible','off')
|
rmeddis@0
|
79 set(handles.pushbutton1,'visible','off')
|
rmeddis@0
|
80 set(handles.pushbutton0,'visible','off')
|
rmeddis@0
|
81 pause(.1)
|
rmeddis@0
|
82 end
|
rmeddis@0
|
83 end
|
rmeddis@0
|
84
|
rmeddis@0
|
85 set(handles.textMSG,'BackgroundColor','w', 'ForegroundColor', 'b')
|
rmeddis@17
|
86
|
rmeddis@0
|
87 % Now the serious business of crafting and presenting the stimulus
|
rmeddis@0
|
88 errormsg= stimulusMakeAndPlay (handles);
|
rmeddis@0
|
89
|
rmeddis@0
|
90 if ~isempty(errormsg)
|
rmeddis@0
|
91 % e.g. clipping. subjGUI will service the error
|
rmeddis@0
|
92 return
|
rmeddis@0
|
93 end
|
rmeddis@0
|
94
|
rmeddis@0
|
95 % after playing the stimulus, reset the subjectGUI
|
rmeddis@0
|
96 switch experiment.ear
|
rmeddis@0
|
97 case {'statsModelLogistic', 'statsModelRareEvent',...
|
rmeddis@0
|
98 'MAPmodel', 'MAPmodelMultiCh', 'MAPmodelSingleCh'}
|
rmeddis@0
|
99 % no changes required if model used
|
rmeddis@0
|
100 % NB these changes do occur is 'MAPmodelListen' is selected
|
rmeddis@0
|
101 otherwise
|
rmeddis@0
|
102 switch experiment.threshEstMethod
|
rmeddis@0
|
103 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@0
|
104 % buttons already visible
|
rmeddis@0
|
105 otherwise
|
rmeddis@0
|
106 % single interval now make buttons visible
|
rmeddis@0
|
107 set(handles.frame1,'visible','on')
|
rmeddis@0
|
108 set(handles.pushbuttoNotSure,'visible','on')
|
rmeddis@0
|
109 % set(handles.pushbuttonWrongButton,'visible','on')
|
rmeddis@0
|
110 set(handles.pushbutton0,'visible','on')
|
rmeddis@0
|
111 set(handles.pushbutton1,'visible','on')
|
rmeddis@0
|
112 set(handles.pushbutton2,'visible','on')
|
rmeddis@0
|
113 set(handles.pushbutton3,'visible','on')
|
rmeddis@0
|
114 end
|
rmeddis@0
|
115 end
|
rmeddis@0
|
116
|
rmeddis@0
|
117 switch experiment.paradigm
|
rmeddis@0
|
118 case 'SRT'
|
rmeddis@0
|
119 set(handles.frame1,'backgroundColor','w')
|
rmeddis@0
|
120 set(handles.frame1,'visible','off')
|
rmeddis@0
|
121 set(handles.pushbuttoNotSure,'visible','off')
|
rmeddis@0
|
122 set(handles.pushbuttonWrongButton,'visible','off')
|
rmeddis@0
|
123 set(handles.pushbutton3,'visible','off')
|
rmeddis@0
|
124 set(handles.pushbutton2,'visible','off')
|
rmeddis@0
|
125 set(handles.pushbutton1,'visible','off')
|
rmeddis@0
|
126 set(handles.pushbutton0,'visible','off')
|
rmeddis@0
|
127 set(handles.editdigitInput,'visible','on')
|
rmeddis@0
|
128 set(handles.editdigitInput,'string',[])
|
rmeddis@0
|
129 pause(.2)
|
rmeddis@0
|
130 uicontrol(handles.editdigitInput)
|
rmeddis@0
|
131
|
rmeddis@0
|
132 otherwise
|
rmeddis@0
|
133 set(handles.editdigitInput,'visible','off')
|
rmeddis@0
|
134 end
|
rmeddis@0
|
135
|
rmeddis@0
|
136
|
rmeddis@0
|
137 experiment.status='waitingForResponse';
|
rmeddis@0
|
138 % home again
|
rmeddis@0
|
139
|
rmeddis@0
|
140 % ------------------------------------------------------------------------------------------stimulusMakeAndPlay
|
rmeddis@0
|
141 function errormsg=stimulusMakeAndPlay (handles)
|
rmeddis@0
|
142 global experiment stimulusParameters betweenRuns withinRuns expGUIhandles audio
|
rmeddis@0
|
143 % creates the stimulus and plays it; there are two stimuli; cue and test
|
rmeddis@0
|
144 % called from nextStimulus
|
rmeddis@0
|
145
|
rmeddis@0
|
146 errormsg='';
|
rmeddis@0
|
147
|
rmeddis@0
|
148 % first post the subjects instructions on subjGUI
|
rmeddis@0
|
149 set(handles.textMSG,'string', stimulusParameters.subjectText)
|
rmeddis@0
|
150
|
rmeddis@0
|
151 % select the new levels of the between runs variables
|
rmeddis@35
|
152 thisRunNumber=betweenRuns.runNumber;
|
rmeddis@0
|
153 cmd=(['stimulusParameters.' betweenRuns.variableName1 '= ' ...
|
rmeddis@35
|
154 num2str(betweenRuns.var1Sequence(thisRunNumber)) ';']);
|
rmeddis@0
|
155 % e.g. stimulusParameters.targetFrequency= 1000;
|
rmeddis@0
|
156 eval(cmd);
|
rmeddis@0
|
157
|
rmeddis@0
|
158 cmd=(['stimulusParameters.' betweenRuns.variableName2 '= ' ...
|
rmeddis@35
|
159 num2str(betweenRuns.var2Sequence(thisRunNumber)) ';']);
|
rmeddis@0
|
160 % e.g. stimulusParameters.targetDuration= 0.1;
|
rmeddis@0
|
161 eval(cmd);
|
rmeddis@0
|
162
|
rmeddis@35
|
163 % When variableList2 is 'targetFrequency' targetLevel may vary between runs
|
rmeddis@35
|
164 % If so, it is changed at the end of each variableList1.
|
rmeddis@36
|
165 if strcmp(betweenRuns.variableName2, 'targetFrequency') && ...
|
rmeddis@35
|
166 length(stimulusParameters.targetLevels)>1
|
rmeddis@35
|
167 switch experiment.paradigm
|
rmeddis@35
|
168 case {'trainingIFMC', 'TMC','TMC_16ms', 'TMC - ELP', 'IFMC','IFMC_8ms','IFMC_16ms'}
|
rmeddis@35
|
169 idx=floor(thisRunNumber/length(betweenRuns.variableList1)-0.01)+1;
|
rmeddis@35
|
170 cmd=(['stimulusParameters.targetLevel = ' ...
|
rmeddis@35
|
171 num2str(stimulusParameters.targetLevels(idx)) ';']);
|
rmeddis@35
|
172 eval(cmd);
|
rmeddis@35
|
173 if withinRuns.trialNumber==1
|
rmeddis@35
|
174 disp(['targetLevel=' num2str(stimulusParameters.targetLevel)])
|
rmeddis@35
|
175 end
|
rmeddis@35
|
176 end
|
rmeddis@0
|
177 end
|
rmeddis@0
|
178
|
rmeddis@0
|
179
|
rmeddis@0
|
180 % for more readable code use shorter variable names;
|
rmeddis@0
|
181 % NB these may change below; these are only the starting values
|
rmeddis@0
|
182
|
rmeddis@0
|
183 targetType= stimulusParameters.targetType;
|
rmeddis@0
|
184 targetDuration= stimulusParameters.targetDuration;
|
rmeddis@0
|
185 targetLevel= stimulusParameters.targetLevel;
|
rmeddis@0
|
186 targetFrequency= stimulusParameters.targetFrequency;
|
rmeddis@0
|
187
|
rmeddis@0
|
188 maskerType= stimulusParameters.maskerType;
|
rmeddis@0
|
189 maskerDuration= stimulusParameters.maskerDuration;
|
rmeddis@0
|
190 maskerLevel= stimulusParameters.maskerLevel;
|
rmeddis@0
|
191 maskerRelativeFrequency= stimulusParameters.maskerRelativeFrequency;
|
rmeddis@0
|
192 maskerFrequency= maskerRelativeFrequency*targetFrequency;
|
rmeddis@0
|
193
|
rmeddis@0
|
194 gapDuration= stimulusParameters.gapDuration;
|
rmeddis@0
|
195
|
rmeddis@0
|
196 rampDuration= stimulusParameters.rampDuration;
|
rmeddis@0
|
197 AFCsilenceDuration=stimulusParameters.AFCsilenceDuration; % 2I2AFC gap
|
rmeddis@0
|
198 backgroundLevel= stimulusParameters.backgroundLevel;
|
rmeddis@0
|
199
|
rmeddis@0
|
200 % Set level of within runs variable
|
rmeddis@0
|
201 % this is the first change to one of the values shown above
|
rmeddis@0
|
202 cmd=[stimulusParameters.WRVname '= withinRuns.variableValue;' ];
|
rmeddis@0
|
203 % e.g.: maskerLevel= withinRuns.variableValue;
|
rmeddis@0
|
204 eval(cmd);
|
rmeddis@0
|
205
|
rmeddis@0
|
206 % cue and test stimuli are identical except for a single difference
|
rmeddis@0
|
207 % depending on the paradigm
|
rmeddis@0
|
208 cueTestDifference= stimulusParameters.cueTestDifference;
|
rmeddis@0
|
209 % cue characteristics before adding cue differences
|
rmeddis@0
|
210 cueTargetLevel=targetLevel;
|
rmeddis@0
|
211 cueMaskerFrequency=maskerFrequency;
|
rmeddis@0
|
212 cueMaskerDuration=maskerDuration;
|
rmeddis@0
|
213 cueMaskerLevel=maskerLevel;
|
rmeddis@0
|
214 cueTargetFrequency=targetFrequency;
|
rmeddis@0
|
215 cueGapDuration=gapDuration;
|
rmeddis@0
|
216
|
rmeddis@0
|
217 % ----------------------------paradigm sensitive cue and masker settings
|
rmeddis@0
|
218 % switch off unwanted components and base cue on target values
|
rmeddis@0
|
219 % for catch trials switch off the target
|
rmeddis@0
|
220
|
rmeddis@0
|
221 % --- set cueTarget level according to assessment method
|
rmeddis@0
|
222 % cue-test difference applies only with singleInterval
|
rmeddis@0
|
223 switch experiment.threshEstMethod
|
rmeddis@0
|
224 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@0
|
225 % For 2IFC the cue stimulus (masker + probe) is the 'no' window
|
rmeddis@0
|
226 % and the target stimulus (masker+probe) is the 'yes' window
|
rmeddis@0
|
227 % the order of presentation is decided at the last minute.
|
rmeddis@0
|
228 cueTargetLevel=-100; % the target is never in the 'no' window
|
rmeddis@0
|
229 cueMaskerLevel=maskerLevel; % masker level is the same in both
|
rmeddis@0
|
230 otherwise
|
rmeddis@0
|
231 % 'single interval' or max likelihood
|
rmeddis@0
|
232 switch experiment.paradigm
|
rmeddis@0
|
233 % cue target is more audible
|
rmeddis@0
|
234 case {'training','absThreshold', 'absThreshold_8', ...
|
rmeddis@0
|
235 'TENtest', 'threshold_duration','discomfort',...
|
rmeddis@0
|
236 'overShoot','overShootB','overShootMB1', ...
|
rmeddis@38
|
237 'overShootMB2', 'OHIO','OHIOabs','OHIOspect'...
|
rmeddis@38
|
238 'OHIOrand', 'OHIOtemp', 'OHIOspectemp'}
|
rmeddis@0
|
239 cueTargetLevel=targetLevel+cueTestDifference;
|
rmeddis@0
|
240
|
rmeddis@0
|
241 case {'forwardMasking','forwardMaskingD','trainingIFMC', ...
|
rmeddis@38
|
242 'TMC','TMC_16ms', 'TMC - ELP', 'IFMC','IFMC_8ms', ...
|
rmeddis@38
|
243 'FMreProbe'}
|
rmeddis@0
|
244 % cue masker is weaker to make target more audible
|
rmeddis@0
|
245 cueMaskerLevel=maskerLevel-cueTestDifference;
|
rmeddis@0
|
246 end
|
rmeddis@0
|
247 end
|
rmeddis@0
|
248
|
rmeddis@38
|
249 % thresholds (in dB SPL) of the single tone with 12 frequencies:
|
rmeddis@38
|
250 % 1 2 3 4 5 6 7 8 9 10 11 12
|
rmeddis@38
|
251 % 494, 663, 870, 1125, 1442, 1838, 2338, 2957, 3725, 4689, 5866, 7334
|
rmeddis@38
|
252
|
rmeddis@38
|
253 % 2. ‘OHIOtemp’ is for measuring thresholds for temporally integrated
|
rmeddis@38
|
254 % combinations of 2, 4, 8, and 12 tones presented simultaneously.
|
rmeddis@38
|
255 % In our experiment, we used 4680Hz frequency.
|
rmeddis@38
|
256
|
rmeddis@38
|
257 % 3. ‘OHIOspec’ is for measuring thresholds for spectrally integrated
|
rmeddis@38
|
258 % combinations of 2(7335 and 5866Hz), 4(7334, 5866, 4680, and 3725Hz),
|
rmeddis@38
|
259 % 8(7334, 5866, 4680, 3725, 2957, 2338, 1838, and
|
rmeddis@38
|
260 % 1442Hz), and
|
rmeddis@38
|
261 % 12(all 12 frequencies) tones presented simultaneously.
|
rmeddis@38
|
262
|
rmeddis@38
|
263 % 4. ‘OHIOspectemp’ is for measuring thresholds for patterned signals
|
rmeddis@38
|
264 % differing in both the spectral and temporal domains.
|
rmeddis@38
|
265 % The frequency conditions are the same as that of ‘OHIOspec’.
|
rmeddis@38
|
266
|
rmeddis@38
|
267 % 5. ‘OHIOrand’ is for measuring thresholds for spectrotemporally varying
|
rmeddis@38
|
268 % signals with random frequency presentation.
|
rmeddis@38
|
269
|
rmeddis@38
|
270 switch experiment.paradigm(1:3)
|
rmeddis@38
|
271 case 'OHI'
|
rmeddis@38
|
272 targetType='OHIO';
|
rmeddis@38
|
273 OHIOtype=experiment.paradigm;
|
rmeddis@38
|
274 % 1. ‘OHIOabs’ paradigm is a baseline procedure for measuring absolute
|
rmeddis@38
|
275
|
rmeddis@38
|
276 nTones=betweenRuns.var1Sequence(betweenRuns.runNumber);
|
rmeddis@38
|
277 allFreqs=[494, 663, 870, 1125, 1442, 1838, 2338, 2957, 3725, 4689, 5866, 7334];
|
rmeddis@38
|
278 toneLevelBoost= ...
|
rmeddis@38
|
279 [1 0 0 1 1 4 8 12 12 14 17 19 ];
|
rmeddis@38
|
280
|
rmeddis@38
|
281
|
rmeddis@38
|
282 % for nTones=nTonesList
|
rmeddis@38
|
283 switch experiment.paradigm
|
rmeddis@38
|
284 % case ' OHIOabs'
|
rmeddis@38
|
285 % % one tone frequency at a time
|
rmeddis@38
|
286 % stim.frequencies=allFreqs(1);
|
rmeddis@38
|
287 % stim.amplitudesdB=0;
|
rmeddis@38
|
288
|
rmeddis@38
|
289 case 'OHIOrand'
|
rmeddis@38
|
290 % chose nTones frequencies at random
|
rmeddis@38
|
291 x=rand(1,12);
|
rmeddis@38
|
292 [sorted idx]=sort(x);
|
rmeddis@38
|
293 cueTargetFrequency=allFreqs(idx(1:nTones));
|
rmeddis@38
|
294 cueTargetLevel=toneLevelBoost(idx)+...
|
rmeddis@38
|
295 targetLevel + cueTestDifference;
|
rmeddis@38
|
296 targetFrequency=allFreqs(idx(1:nTones));
|
rmeddis@38
|
297 targetLevel=targetLevel + toneLevelBoost(idx);
|
rmeddis@38
|
298
|
rmeddis@38
|
299 case 'OHIOtemp'
|
rmeddis@38
|
300 % 4680 Hz repeated nTones times
|
rmeddis@38
|
301 cueTargetFrequency=4680*ones(1,nTones);
|
rmeddis@38
|
302 cueTargetLevel=repmat(toneLevelBoost(10),1,nTones)+...
|
rmeddis@38
|
303 targetLevel + cueTestDifference;
|
rmeddis@38
|
304 targetFrequency=4680*ones(1,nTones);
|
rmeddis@38
|
305 targetLevel= targetLevel+repmat(toneLevelBoost(10),1,nTones);
|
rmeddis@38
|
306
|
rmeddis@38
|
307 case {'OHIOspect', 'OHIOspectemp'}
|
rmeddis@38
|
308 % nTones frequencies either simulataneously or sequentially
|
rmeddis@38
|
309 switch nTones
|
rmeddis@38
|
310 case 2
|
rmeddis@38
|
311 cueTargetFrequency=[7335 5866];
|
rmeddis@38
|
312 targetFrequency=[7335 5866];
|
rmeddis@38
|
313 idx=[12 11];
|
rmeddis@38
|
314 cueTargetLevel=targetLevel + toneLevelBoost(idx)+cueTestDifference;
|
rmeddis@38
|
315 targetLevel=targetLevel + toneLevelBoost(idx);
|
rmeddis@38
|
316 case 4
|
rmeddis@38
|
317 cueTargetFrequency=[7334, 5866, 4680, 3725];
|
rmeddis@38
|
318 targetFrequency=[7334, 5866, 4680, 3725];
|
rmeddis@38
|
319 idx=[12:-1:9 ];
|
rmeddis@38
|
320 cueTargetLevel=targetLevel + toneLevelBoost(idx)+cueTestDifference;
|
rmeddis@38
|
321 targetLevel=targetLevel + toneLevelBoost(idx);
|
rmeddis@38
|
322 case 8
|
rmeddis@38
|
323 cueTargetFrequency=...
|
rmeddis@38
|
324 [7334, 5866, 4680, 3725, 2957, 2338, 1838, 1442];
|
rmeddis@38
|
325 targetFrequency=...
|
rmeddis@38
|
326 [7334, 5866, 4680, 3725, 2957, 2338, 1838, 1442];
|
rmeddis@38
|
327 idx=[12:-1:5 ];
|
rmeddis@38
|
328 cueTargetLevel=targetLevel + toneLevelBoost(idx)+cueTestDifference;
|
rmeddis@38
|
329 targetLevel=targetLevel + toneLevelBoost(idx);
|
rmeddis@38
|
330 case 12
|
rmeddis@38
|
331 cueTargetFrequency=allFreqs;
|
rmeddis@38
|
332 targetFrequency=allFreqs;
|
rmeddis@38
|
333 cueTargetLevel=targetLevel + toneLevelBoost(1:12)+cueTestDifference;
|
rmeddis@38
|
334 targetLevel=targetLevel + toneLevelBoost(1:12);
|
rmeddis@38
|
335 end
|
rmeddis@38
|
336 end
|
rmeddis@38
|
337
|
rmeddis@38
|
338 otherwise
|
rmeddis@38
|
339 OHIOtype='none';
|
rmeddis@38
|
340 end
|
rmeddis@38
|
341
|
rmeddis@38
|
342 switch experiment.paradigm(1:3)
|
rmeddis@38
|
343 case 'OHI'
|
rmeddis@38
|
344
|
rmeddis@38
|
345 switch experiment.threshEstMethod
|
rmeddis@38
|
346 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@38
|
347 % the cue stimulus (masker + probe) is the 'no' window
|
rmeddis@38
|
348 % the target stimulus (masker+probe) is the 'yes' window
|
rmeddis@38
|
349 % the order of presentation is decided at the last minute.
|
rmeddis@38
|
350 cueTargetLevel=-100;
|
rmeddis@38
|
351 end
|
rmeddis@38
|
352
|
rmeddis@38
|
353
|
rmeddis@38
|
354 switch experiment.paradigm
|
rmeddis@38
|
355 case {'OHIOabs', 'OHIOspect'}
|
rmeddis@38
|
356 OHIOtoneDuration=.02+stimulusParameters.stimulusDelay;
|
rmeddis@38
|
357 globalStimParams.overallDuration=OHIOtoneDuration;
|
rmeddis@38
|
358 otherwise
|
rmeddis@38
|
359 OHIOtoneDuration=nTones*0.02+stimulusParameters.stimulusDelay;
|
rmeddis@38
|
360 globalStimParams.overallDuration=OHIOtoneDuration;
|
rmeddis@38
|
361 end
|
rmeddis@38
|
362 end
|
rmeddis@38
|
363
|
rmeddis@0
|
364 % ----------------------------- catch trial
|
rmeddis@0
|
365 if withinRuns.catchTrial
|
rmeddis@0
|
366 targetLevel=-100; % no target
|
rmeddis@0
|
367 end
|
rmeddis@0
|
368
|
rmeddis@17
|
369 % ----------------------------- calibration of sound output
|
rmeddis@35
|
370 % seperate calibration for each frequency to match headphones
|
rmeddis@17
|
371 calibrationCorrectiondB=stimulusParameters.calibrationdB;
|
rmeddis@17
|
372 if calibrationCorrectiondB<-50
|
rmeddis@17
|
373 if maskerFrequency==targetFrequency
|
rmeddis@17
|
374 load 'calibrationFile' % calibrationFrequency calibrationAttenutation
|
rmeddis@17
|
375 idx=find(calibrationFrequency==targetFrequency);
|
rmeddis@17
|
376 if isempty(idx)
|
rmeddis@35
|
377 error('Calibration by file; frequency not found')
|
rmeddis@17
|
378 else
|
rmeddis@17
|
379 calibrationCorrectiondB=calibrationAttenutation(idx)
|
rmeddis@17
|
380 end
|
rmeddis@17
|
381 else
|
rmeddis@17
|
382 error('calibration by file requested but masker frequency is not the same as target')
|
rmeddis@17
|
383 end
|
rmeddis@17
|
384 end
|
rmeddis@17
|
385
|
rmeddis@17
|
386
|
rmeddis@0
|
387 % -------------------------------------- Checks on excessive signal level
|
rmeddis@0
|
388
|
rmeddis@0
|
389 % clipping is relevant only for soundcard use (not modelling)
|
rmeddis@0
|
390 switch experiment.ear
|
rmeddis@0
|
391 case {'left', 'right', 'diotic',...
|
rmeddis@0
|
392 'dichotic', 'dioticLeft', 'dichoticRight'}
|
rmeddis@0
|
393 experiment.headphonesUsed=1;
|
rmeddis@0
|
394 otherwise
|
rmeddis@0
|
395 experiment.headphonesUsed=0;
|
rmeddis@0
|
396 end
|
rmeddis@0
|
397
|
rmeddis@0
|
398 % NB calibration *reduces* the level of the soundCard output
|
rmeddis@0
|
399 switch experiment.ear
|
rmeddis@0
|
400 case {'left', 'right', 'diotic',...
|
rmeddis@0
|
401 'dichotic', 'dioticLeft', 'dichoticRight'}
|
rmeddis@17
|
402 clippingLevel=91+calibrationCorrectiondB;
|
rmeddis@0
|
403 soundCardMinimum=clippingLevel-20*log10(2^24);
|
rmeddis@0
|
404 otherwise
|
rmeddis@0
|
405 clippingLevel=inf;
|
rmeddis@0
|
406 soundCardMinimum=-inf;
|
rmeddis@0
|
407 end
|
rmeddis@0
|
408
|
rmeddis@0
|
409 % Check for extreme WRV values and abort if necessary
|
rmeddis@0
|
410 % WRVname specifies the value that changes from trial to trial
|
rmeddis@0
|
411 withinRuns.forceThreshold=[];
|
rmeddis@0
|
412 switch stimulusParameters.WRVname
|
rmeddis@0
|
413 % check for extreme values. Note that one of the tones might be switched off
|
rmeddis@0
|
414 case 'maskerLevel'
|
rmeddis@0
|
415 upperLevel=stimulusParameters.WRVlimits(2);
|
rmeddis@0
|
416 lowerLevel=stimulusParameters.WRVlimits(1);
|
rmeddis@0
|
417 if max(maskerLevel, cueMaskerLevel)> upperLevel
|
rmeddis@0
|
418 errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ...
|
rmeddis@0
|
419 ') is too high ***'];
|
rmeddis@0
|
420 withinRuns.forceThreshold=upperLevel;
|
rmeddis@0
|
421 withinRuns.forceThreshold=NaN;
|
rmeddis@0
|
422 return
|
rmeddis@0
|
423 end
|
rmeddis@0
|
424 if max(maskerLevel, cueMaskerLevel)< lowerLevel
|
rmeddis@0
|
425 errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ...
|
rmeddis@0
|
426 ') is too low ***'];
|
rmeddis@0
|
427 withinRuns.forceThreshold=lowerLevel;
|
rmeddis@0
|
428 withinRuns.forceThreshold=NaN;
|
rmeddis@0
|
429 return
|
rmeddis@0
|
430 end
|
rmeddis@0
|
431
|
rmeddis@0
|
432 if max(maskerLevel, cueMaskerLevel)> clippingLevel
|
rmeddis@0
|
433 errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ...
|
rmeddis@0
|
434 ') is clipping ***'];
|
rmeddis@0
|
435 withinRuns.forceThreshold=clippingLevel;
|
rmeddis@0
|
436 withinRuns.forceThreshold=NaN;
|
rmeddis@0
|
437 return
|
rmeddis@0
|
438 end
|
rmeddis@17
|
439
|
rmeddis@0
|
440 case 'targetLevel'
|
rmeddis@0
|
441 upperLevel=stimulusParameters.WRVlimits(2);
|
rmeddis@0
|
442 lowerLevel=stimulusParameters.WRVlimits(1);
|
rmeddis@0
|
443 if ~withinRuns.catchTrial
|
rmeddis@0
|
444 if max(targetLevel, cueTargetLevel)> upperLevel
|
rmeddis@0
|
445 errormsg=['target level (' ...
|
rmeddis@0
|
446 num2str(max(targetLevel, cueTargetLevel)) ...
|
rmeddis@0
|
447 ') is too high ***'];
|
rmeddis@0
|
448 withinRuns.forceThreshold=upperLevel;
|
rmeddis@17
|
449 withinRuns.forceThreshold=NaN;
|
rmeddis@0
|
450 return
|
rmeddis@0
|
451 end
|
rmeddis@0
|
452 if max(targetLevel, cueTargetLevel)< lowerLevel
|
rmeddis@0
|
453 errormsg=['target level (' ...
|
rmeddis@0
|
454 num2str(max(targetLevel, cueTargetLevel)) ...
|
rmeddis@0
|
455 ') is too low ***'];
|
rmeddis@0
|
456 withinRuns.forceThreshold=lowerLevel;
|
rmeddis@17
|
457 withinRuns.forceThreshold=NaN;
|
rmeddis@0
|
458 return
|
rmeddis@0
|
459 end
|
rmeddis@0
|
460 if max(targetLevel, cueTargetLevel)> clippingLevel
|
rmeddis@0
|
461 errormsg=['target level (' ...
|
rmeddis@0
|
462 num2str(max(targetLevel, cueTargetLevel)) ...
|
rmeddis@0
|
463 ') is clipping ***'];
|
rmeddis@0
|
464 withinRuns.forceThreshold=upperLevel;
|
rmeddis@17
|
465 withinRuns.forceThreshold=NaN;
|
rmeddis@0
|
466 return
|
rmeddis@0
|
467 end
|
rmeddis@17
|
468 end
|
rmeddis@0
|
469 case 'maskerDuration'
|
rmeddis@0
|
470 % this is odd! but harmless
|
rmeddis@0
|
471 if max(maskerDuration, cueMaskerDuration)> ...
|
rmeddis@0
|
472 stimulusParameters.WRVlimits(2)
|
rmeddis@0
|
473 errormsg=['maskerDuration (' ...
|
rmeddis@0
|
474 num2str(max(maskerDuration, cueMaskerDuration))...
|
rmeddis@0
|
475 ') is too long ***'];
|
rmeddis@0
|
476 withinRuns.forceThreshold=stimulusParameters.WRVlimits(2);
|
rmeddis@0
|
477 withinRuns.forceThreshold=NaN;
|
rmeddis@0
|
478 return
|
rmeddis@0
|
479 end
|
rmeddis@0
|
480
|
rmeddis@0
|
481 if min(maskerDuration, cueMaskerDuration)...
|
rmeddis@0
|
482 < stimulusParameters.WRVlimits(1)
|
rmeddis@0
|
483 errormsg=['maskerDuration (' num2str(maskerLevel) ...
|
rmeddis@0
|
484 ') too short ***'];
|
rmeddis@0
|
485 withinRuns.forceThreshold=stimulusParameters.WRVlimits(1);
|
rmeddis@0
|
486 withinRuns.forceThreshold=NaN;
|
rmeddis@0
|
487 return
|
rmeddis@0
|
488 end
|
rmeddis@0
|
489
|
rmeddis@38
|
490 case 'gapDuration'
|
rmeddis@0
|
491 % legacy programming
|
rmeddis@0
|
492 if gapDuration<0
|
rmeddis@0
|
493 errormsg=['gapDuration (' num2str(gapDuration) ...
|
rmeddis@0
|
494 ') is less than zero ***'];
|
rmeddis@0
|
495 return
|
rmeddis@0
|
496 end
|
rmeddis@0
|
497
|
rmeddis@0
|
498 case 'maskerFrequency'
|
rmeddis@0
|
499 switch experiment.paradigm
|
rmeddis@0
|
500 case 'bandwidth'
|
rmeddis@0
|
501 frequency=maskerFrequency';
|
rmeddis@0
|
502 if stimulusParameters.WRVstep<0
|
rmeddis@0
|
503 lowerLevel=stimulusParameters.targetFrequency;
|
rmeddis@0
|
504 upperLevel=stimulusParameters.targetFrequency*2;
|
rmeddis@0
|
505 else
|
rmeddis@0
|
506 lowerLevel=stimulusParameters.targetFrequency/3;
|
rmeddis@0
|
507 upperLevel=stimulusParameters.targetFrequency;
|
rmeddis@0
|
508 end
|
rmeddis@0
|
509
|
rmeddis@0
|
510 if frequency(1)>upperLevel || frequency(1)<lowerLevel
|
rmeddis@0
|
511 errormsg=['frequency out of range: ' ...
|
rmeddis@0
|
512 num2str(frequency)];
|
rmeddis@0
|
513 withinRuns.forceThreshold=frequency;
|
rmeddis@0
|
514 return
|
rmeddis@0
|
515 end
|
rmeddis@0
|
516 otherwise
|
rmeddis@0
|
517 end
|
rmeddis@0
|
518
|
rmeddis@0
|
519 case 'maskerRelativeFrequency'
|
rmeddis@0
|
520 if maskerRelativeFrequency<stimulusParameters.WRVlimits(1)
|
rmeddis@0
|
521 errormsg=['masker frequency (' ...
|
rmeddis@0
|
522 num2str(frequencyDifference) ...
|
rmeddis@0
|
523 ') is outside WRV limits ***'];
|
rmeddis@0
|
524 withinRuns.forceThreshold=stimulusParameters.WRVlimits(1) ;
|
rmeddis@0
|
525 return
|
rmeddis@0
|
526 end
|
rmeddis@0
|
527 if maskerRelativeFrequency>stimulusParameters.WRVlimits(2)
|
rmeddis@0
|
528 errormsg=['masker frequency (' ...
|
rmeddis@0
|
529 num2str(frequencyDifference) ...
|
rmeddis@0
|
530 ') is outside WRV limits ***'];
|
rmeddis@0
|
531 withinRuns.forceThreshold=stimulusParameters.WRVlimits(2) ;
|
rmeddis@0
|
532 return
|
rmeddis@0
|
533 end
|
rmeddis@0
|
534
|
rmeddis@0
|
535 end
|
rmeddis@0
|
536
|
rmeddis@0
|
537 % --------------------------------Ear ----------------------------------
|
rmeddis@0
|
538 globalStimParams.ears='specified';
|
rmeddis@0
|
539 % ear: 1=left, 2=right
|
rmeddis@0
|
540 switch experiment.ear
|
rmeddis@0
|
541 case 'left'
|
rmeddis@0
|
542 maskerEar=1;
|
rmeddis@0
|
543 targetEar=1;
|
rmeddis@0
|
544 case 'right'
|
rmeddis@0
|
545 maskerEar=2;
|
rmeddis@0
|
546 targetEar=2;
|
rmeddis@0
|
547 case 'dichoticLeft'
|
rmeddis@0
|
548 maskerEar=2;
|
rmeddis@0
|
549 targetEar=1;
|
rmeddis@0
|
550 case 'dichoticRight'
|
rmeddis@0
|
551 maskerEar=1;
|
rmeddis@0
|
552 targetEar=2;
|
rmeddis@0
|
553 case 'diotic'
|
rmeddis@0
|
554 maskerEar=1;
|
rmeddis@0
|
555 targetEar=1;
|
rmeddis@0
|
556 globalStimParams.ears='diotic';
|
rmeddis@0
|
557 case {'MAPmodel', 'MAPmodelMultiCh', 'MAPmodelSingleCh', 'MAPmodelListen',...
|
rmeddis@0
|
558 'statsModelLogistic', 'statsModelRareEvent'}
|
rmeddis@0
|
559 maskerEar=1;
|
rmeddis@0
|
560 targetEar=1;
|
rmeddis@0
|
561 end
|
rmeddis@0
|
562
|
rmeddis@0
|
563 backgroundType=stimulusParameters.backgroundType;
|
rmeddis@0
|
564 switch stimulusParameters.backgroundType
|
rmeddis@0
|
565 case {'noiseDich', 'pinkNoiseDich'}
|
rmeddis@17
|
566 % case 'Dich'
|
rmeddis@0
|
567 % dich means put the background in the ear opposite to the target
|
rmeddis@0
|
568 backgroundType=backgroundType(1:end-4);
|
rmeddis@0
|
569 switch targetEar
|
rmeddis@0
|
570 case 1
|
rmeddis@0
|
571 backgroundEar=2;
|
rmeddis@0
|
572 case 2
|
rmeddis@0
|
573 backgroundEar=1;
|
rmeddis@0
|
574 end
|
rmeddis@0
|
575 otherwise
|
rmeddis@17
|
576 % case {'none','noise', 'pinkNoise', 'TEN','babble'}
|
rmeddis@0
|
577 backgroundEar=targetEar;
|
rmeddis@0
|
578 end
|
rmeddis@0
|
579
|
rmeddis@0
|
580 % ------------------------------- Make Stimulus -------------------
|
rmeddis@0
|
581 % single interval up/down plays cue then target stimulus
|
rmeddis@0
|
582 % 2IFC uses cue stimulus as interval with no target
|
rmeddis@0
|
583 globalStimParams.FS=stimulusParameters.sampleRate;
|
rmeddis@0
|
584 dt=1/stimulusParameters.sampleRate;
|
rmeddis@0
|
585 globalStimParams.dt=dt;
|
rmeddis@0
|
586 stimulusParameters.dt=dt; % for use later
|
rmeddis@0
|
587
|
rmeddis@17
|
588
|
rmeddis@17
|
589
|
rmeddis@17
|
590 globalStimParams.audioOutCorrection=10^(calibrationCorrectiondB/20);
|
rmeddis@0
|
591 % the output will be reduced by this amount in stimulusCreate
|
rmeddis@0
|
592 % i.e. audio=audio/globalStimParams.audioOutCorrection
|
rmeddis@0
|
593 % A 91 dB level will yield a peak amp of 1 for calibration=0
|
rmeddis@0
|
594 % A 91 dB level will yield a peak amp of 0.4467 for calibration=7
|
rmeddis@0
|
595 % A 98 dB level will yield a peak amp of 1 for calibration=7
|
rmeddis@0
|
596
|
rmeddis@0
|
597 precedingSilence=stimulusParameters.stimulusDelay;
|
rmeddis@0
|
598 % all stimuli have 20 ms terminal silence.
|
rmeddis@0
|
599 % this is clearance for modelling late-ringing targets
|
rmeddis@0
|
600 terminalSilence=.03;
|
rmeddis@0
|
601
|
rmeddis@0
|
602 % Now compute overall duration of the stimulus
|
rmeddis@0
|
603 % note that all endsilence values are set to -1
|
rmeddis@0
|
604 % so that they will fill with terminal silence as required to make
|
rmeddis@0
|
605 % components equal in length
|
rmeddis@0
|
606 % We need to find the longest possible duration
|
rmeddis@0
|
607 duration(1)=precedingSilence+maskerDuration+cueGapDuration...
|
rmeddis@0
|
608 +targetDuration+terminalSilence;
|
rmeddis@0
|
609 duration(2)=precedingSilence+maskerDuration+gapDuration...
|
rmeddis@0
|
610 +targetDuration+ terminalSilence;
|
rmeddis@0
|
611 % If the gap is negative we need to ignore it when estimating total length
|
rmeddis@0
|
612 duration(3)=precedingSilence+maskerDuration+ terminalSilence;
|
rmeddis@0
|
613 globalStimParams.overallDuration=max(duration);
|
rmeddis@0
|
614 globalStimParams.nSignalPoints=...
|
rmeddis@30
|
615 round(globalStimParams.overallDuration*globalStimParams.FS);
|
rmeddis@0
|
616
|
rmeddis@38
|
617 % special case
|
rmeddis@38
|
618 switch experiment.paradigm(1:3)
|
rmeddis@38
|
619 case 'OHI'
|
rmeddis@38
|
620 switch experiment.paradigm
|
rmeddis@38
|
621 case {'OHIOabs', 'OHIOspect'}
|
rmeddis@38
|
622 OHIOtoneDuration=.02+stimulusParameters.stimulusDelay;
|
rmeddis@38
|
623 globalStimParams.overallDuration=OHIOtoneDuration;
|
rmeddis@38
|
624 otherwise
|
rmeddis@38
|
625 OHIOtoneDuration=nTones*0.02+stimulusParameters.stimulusDelay;
|
rmeddis@38
|
626 globalStimParams.overallDuration=OHIOtoneDuration;
|
rmeddis@38
|
627 end
|
rmeddis@38
|
628 end
|
rmeddis@38
|
629
|
rmeddis@38
|
630
|
rmeddis@0
|
631 % ----------------------------------------------cue stimulus
|
rmeddis@0
|
632 % cue masker
|
rmeddis@0
|
633 componentNo=1;
|
rmeddis@0
|
634 precedingSilence=stimulusParameters.stimulusDelay;
|
rmeddis@0
|
635 stimComponents(maskerEar,componentNo).type=maskerType;
|
rmeddis@0
|
636 stimComponents(maskerEar,componentNo).toneDuration=cueMaskerDuration;
|
rmeddis@0
|
637 stimComponents(maskerEar,componentNo).frequencies=cueMaskerFrequency;
|
rmeddis@0
|
638 stimComponents(maskerEar,componentNo).amplitudesdB=cueMaskerLevel;
|
rmeddis@0
|
639 stimComponents(maskerEar,componentNo).beginSilence=precedingSilence;
|
rmeddis@0
|
640 stimComponents(maskerEar,componentNo).endSilence=-1;
|
rmeddis@0
|
641 stimComponents(maskerEar,componentNo).AMfrequency=0;
|
rmeddis@0
|
642 stimComponents(maskerEar,componentNo).AMdepth=0;
|
rmeddis@0
|
643 if rampDuration<maskerDuration
|
rmeddis@0
|
644 % ramps must be shorter than the signal
|
rmeddis@0
|
645 stimComponents(maskerEar,componentNo).rampOnDur=rampDuration;
|
rmeddis@0
|
646 stimComponents(maskerEar,componentNo).rampOffDur=rampDuration;
|
rmeddis@0
|
647 else
|
rmeddis@0
|
648 % or squeeze the ramp in
|
rmeddis@0
|
649 stimComponents(maskerEar,componentNo).rampOnDur=maskerDuration/2;
|
rmeddis@0
|
650 stimComponents(maskerEar,componentNo).rampOffDur=maskerDuration/2;
|
rmeddis@0
|
651 end
|
rmeddis@0
|
652 stimComponents(maskerEar,componentNo).phases=...
|
rmeddis@0
|
653 stimulusParameters.maskerPhase;
|
rmeddis@0
|
654 stimComponents(maskerEar,componentNo).niterations=0; % for IRN only
|
rmeddis@0
|
655 % stimComponents(targetEar,componentNo)
|
rmeddis@0
|
656
|
rmeddis@0
|
657 % cue target
|
rmeddis@0
|
658 componentNo=2;
|
rmeddis@0
|
659 precedingSilence=precedingSilence + maskerDuration+cueGapDuration;
|
rmeddis@0
|
660 stimComponents(targetEar,componentNo).type=targetType;
|
rmeddis@38
|
661 stimComponents(targetEar,componentNo).OHIOtype=OHIOtype;
|
rmeddis@0
|
662 stimComponents(targetEar,componentNo).toneDuration=targetDuration;
|
rmeddis@0
|
663 stimComponents(targetEar,componentNo).frequencies=cueTargetFrequency;
|
rmeddis@0
|
664 stimComponents(targetEar,componentNo).amplitudesdB=cueTargetLevel;
|
rmeddis@0
|
665 stimComponents(targetEar,componentNo).beginSilence=precedingSilence;
|
rmeddis@0
|
666 stimComponents(targetEar,componentNo).endSilence=-1;
|
rmeddis@0
|
667 stimComponents(targetEar,componentNo).AMfrequency=0;
|
rmeddis@0
|
668 stimComponents(targetEar,componentNo).AMdepth=0;
|
rmeddis@0
|
669 if rampDuration<targetDuration
|
rmeddis@0
|
670 % ramps must be shorter than the signal
|
rmeddis@0
|
671 stimComponents(targetEar,componentNo).rampOnDur=rampDuration;
|
rmeddis@0
|
672 stimComponents(targetEar,componentNo).rampOffDur=rampDuration;
|
rmeddis@0
|
673 else
|
rmeddis@0
|
674 stimComponents(targetEar,componentNo).rampOnDur=0;
|
rmeddis@0
|
675 stimComponents(targetEar,componentNo).rampOffDur=0;
|
rmeddis@0
|
676 end
|
rmeddis@0
|
677 stimComponents(targetEar,componentNo).phases=...
|
rmeddis@0
|
678 stimulusParameters.targetPhase;
|
rmeddis@0
|
679 % stimComponents(targetEar,componentNo)
|
rmeddis@0
|
680
|
rmeddis@0
|
681 % background same ear as target
|
rmeddis@0
|
682 componentNo=3;
|
rmeddis@0
|
683 stimComponents(backgroundEar,componentNo).type=backgroundType;
|
rmeddis@0
|
684 switch backgroundType
|
rmeddis@0
|
685 case 'TEN'
|
rmeddis@0
|
686 fileName=['..' filesep '..' filesep ...
|
rmeddis@0
|
687 'multithresholdResources' filesep ...
|
rmeddis@0
|
688 'backgrounds and maskers'...
|
rmeddis@0
|
689 filesep 'ten.wav'];
|
rmeddis@0
|
690 [tenNoise, FS]=wavread(fileName);
|
rmeddis@0
|
691 tenNoise=resample(tenNoise, globalStimParams.FS, FS);
|
rmeddis@0
|
692 stimComponents(backgroundEar,componentNo).type='file';
|
rmeddis@0
|
693 stimComponents(backgroundEar,componentNo).stimulus=tenNoise';
|
rmeddis@0
|
694 end
|
rmeddis@0
|
695 stimComponents(backgroundEar,componentNo).toneDuration=...
|
rmeddis@0
|
696 globalStimParams.overallDuration;
|
rmeddis@0
|
697 stimComponents(backgroundEar,componentNo).amplitudesdB=backgroundLevel;
|
rmeddis@0
|
698 stimComponents(backgroundEar,componentNo).beginSilence=0;
|
rmeddis@0
|
699 stimComponents(backgroundEar,componentNo).endSilence=-1;
|
rmeddis@0
|
700 stimComponents(backgroundEar,componentNo).AMfrequency=0;
|
rmeddis@0
|
701 stimComponents(backgroundEar,componentNo).AMdepth=0;
|
rmeddis@0
|
702 stimComponents(backgroundEar,componentNo).rampOnDur=rampDuration;
|
rmeddis@0
|
703 stimComponents(backgroundEar,componentNo).rampOffDur=rampDuration;
|
rmeddis@0
|
704
|
rmeddis@0
|
705 [cueStimulus, errormsg]=...
|
rmeddis@0
|
706 stimulusCreate(globalStimParams, stimComponents, 0);
|
rmeddis@0
|
707 if ~isempty(errormsg) % e.g. limits exceeded
|
rmeddis@0
|
708 errormsg
|
rmeddis@0
|
709 return
|
rmeddis@0
|
710 end
|
rmeddis@0
|
711
|
rmeddis@0
|
712 % ------------------------------------------ test stimulus
|
rmeddis@0
|
713 % masker
|
rmeddis@0
|
714 componentNo=1;
|
rmeddis@0
|
715 precedingSilence=stimulusParameters.stimulusDelay;
|
rmeddis@0
|
716 stimComponents(maskerEar,componentNo).type=maskerType;
|
rmeddis@0
|
717 stimComponents(maskerEar,componentNo).toneDuration=maskerDuration;
|
rmeddis@0
|
718 stimComponents(maskerEar,componentNo).frequencies=maskerFrequency;
|
rmeddis@0
|
719 stimComponents(maskerEar,componentNo).amplitudesdB=maskerLevel;
|
rmeddis@0
|
720 stimComponents(maskerEar,componentNo).beginSilence=precedingSilence;
|
rmeddis@0
|
721 stimComponents(maskerEar,componentNo).endSilence=-1;
|
rmeddis@0
|
722 stimComponents(maskerEar,componentNo).AMfrequency=0;
|
rmeddis@0
|
723 stimComponents(maskerEar,componentNo).AMdepth=0;
|
rmeddis@0
|
724 if rampDuration<maskerDuration
|
rmeddis@0
|
725 % ramps must be shorter than the signal
|
rmeddis@0
|
726 stimComponents(maskerEar,componentNo).rampOnDur=rampDuration;
|
rmeddis@0
|
727 stimComponents(maskerEar,componentNo).rampOffDur=rampDuration;
|
rmeddis@0
|
728 else
|
rmeddis@0
|
729 stimComponents(maskerEar,componentNo).rampOnDur=maskerDuration/2;
|
rmeddis@0
|
730 stimComponents(maskerEar,componentNo).rampOffDur=maskerDuration/2;
|
rmeddis@0
|
731 end
|
rmeddis@0
|
732 stimComponents(maskerEar,componentNo).phases=...
|
rmeddis@0
|
733 stimulusParameters.maskerPhase;
|
rmeddis@0
|
734 stimComponents(maskerEar,componentNo).niterations=0; % for IRN only
|
rmeddis@0
|
735
|
rmeddis@0
|
736 % target
|
rmeddis@0
|
737 componentNo=2;
|
rmeddis@0
|
738 targetDelay=precedingSilence+ maskerDuration+ gapDuration;
|
rmeddis@0
|
739 stimComponents(targetEar,componentNo).type=targetType;
|
rmeddis@38
|
740 stimComponents(targetEar,componentNo).OHIOtype=OHIOtype;
|
rmeddis@0
|
741 stimComponents(targetEar,componentNo).toneDuration=targetDuration;
|
rmeddis@0
|
742 stimComponents(targetEar,componentNo).frequencies=targetFrequency;
|
rmeddis@0
|
743 stimComponents(targetEar,componentNo).amplitudesdB=targetLevel;
|
rmeddis@0
|
744 stimComponents(targetEar,componentNo).beginSilence=targetDelay;
|
rmeddis@0
|
745 stimComponents(targetEar,componentNo).endSilence=-1;
|
rmeddis@0
|
746 stimComponents(targetEar,componentNo).AMfrequency=0;
|
rmeddis@0
|
747 stimComponents(targetEar,componentNo).AMdepth=0;
|
rmeddis@0
|
748 if rampDuration<targetDuration
|
rmeddis@0
|
749 % ramps must be shorter than the signal
|
rmeddis@0
|
750 stimComponents(targetEar,componentNo).rampOnDur=rampDuration;
|
rmeddis@0
|
751 stimComponents(targetEar,componentNo).rampOffDur=rampDuration;
|
rmeddis@0
|
752 else
|
rmeddis@0
|
753 stimComponents(targetEar,componentNo).rampOnDur=0;
|
rmeddis@0
|
754 stimComponents(targetEar,componentNo).rampOffDur=0;
|
rmeddis@0
|
755 end
|
rmeddis@0
|
756 stimComponents(targetEar,componentNo).phases=stimulusParameters.targetPhase;
|
rmeddis@0
|
757 % stimComponents(targetEar,componentNo)
|
rmeddis@0
|
758
|
rmeddis@0
|
759 % background same ear as target
|
rmeddis@0
|
760 componentNo=3;
|
rmeddis@0
|
761 stimComponents(backgroundEar,componentNo).type=backgroundType;
|
rmeddis@0
|
762 switch backgroundType
|
rmeddis@0
|
763 case 'TEN'
|
rmeddis@0
|
764 fileName=['..' filesep '..' filesep ...
|
rmeddis@0
|
765 'multithresholdResources' filesep ...
|
rmeddis@0
|
766 'backgrounds and maskers'...
|
rmeddis@0
|
767 filesep 'ten.wav'];
|
rmeddis@0
|
768 [tenNoise, FS]=wavread(fileName);
|
rmeddis@17
|
769
|
rmeddis@0
|
770 tenNoise=resample(tenNoise, globalStimParams.FS, FS);
|
rmeddis@0
|
771 stimComponents(backgroundEar,componentNo).type='file';
|
rmeddis@0
|
772 stimComponents(backgroundEar,componentNo).stimulus=tenNoise';
|
rmeddis@0
|
773 end
|
rmeddis@0
|
774 stimComponents(backgroundEar,componentNo).toneDuration=...
|
rmeddis@0
|
775 globalStimParams.overallDuration;
|
rmeddis@0
|
776 stimComponents(backgroundEar,componentNo).amplitudesdB=backgroundLevel;
|
rmeddis@0
|
777 stimComponents(backgroundEar,componentNo).beginSilence=0;
|
rmeddis@0
|
778 stimComponents(backgroundEar,componentNo).endSilence=-1;
|
rmeddis@0
|
779 stimComponents(backgroundEar,componentNo).rampOnDur=rampDuration;
|
rmeddis@0
|
780 stimComponents(backgroundEar,componentNo).rampOffDur=rampDuration;
|
rmeddis@0
|
781 stimComponents(backgroundEar,componentNo).AMfrequency=0;
|
rmeddis@0
|
782 stimComponents(backgroundEar,componentNo).AMdepth=0;
|
rmeddis@0
|
783
|
rmeddis@0
|
784 % timings used when evaluating MAP peripheral model
|
rmeddis@0
|
785 % this is the Slope during which spikes are counted
|
rmeddis@0
|
786 switch experiment.paradigm
|
rmeddis@0
|
787 case 'gapDetection'
|
rmeddis@0
|
788 % gap is the 'target' in this case
|
rmeddis@0
|
789 stimulusParameters.testTargetBegins=...
|
rmeddis@0
|
790 stimulusParameters.stimulusDelay...
|
rmeddis@0
|
791 +stimulusParameters.maskerDuration;
|
rmeddis@0
|
792 stimulusParameters.testTargetEnds=...
|
rmeddis@0
|
793 stimulusParameters.testTargetBegins+withinRuns.variableValue;
|
rmeddis@17
|
794 % case 'SRT'
|
rmeddis@17
|
795 % set(handles.editdigitInput,'visible','off')
|
rmeddis@0
|
796 otherwise
|
rmeddis@38
|
797 switch experiment.paradigm(1:3)
|
rmeddis@38
|
798 case 'OHI'
|
rmeddis@38
|
799 stimulusParameters.testTargetBegins=0;
|
rmeddis@38
|
800 stimulusParameters.testTargetEnds=OHIOtoneDuration;
|
rmeddis@38
|
801 otherwise
|
rmeddis@38
|
802 stimulusParameters.testTargetBegins=targetDelay;
|
rmeddis@38
|
803 stimulusParameters.testTargetEnds=targetDelay+targetDuration;
|
rmeddis@38
|
804 end
|
rmeddis@0
|
805 end
|
rmeddis@0
|
806
|
rmeddis@0
|
807 % ------------------------------------------------------------- play!
|
rmeddis@0
|
808 % Create and play stimulus (as required by different paradigms)
|
rmeddis@0
|
809 switch experiment.ear
|
rmeddis@0
|
810 case {'statsModelLogistic', 'statsModelRareEvent'}
|
rmeddis@0
|
811 audio=[0;0]; % no need to compute stimulus
|
rmeddis@0
|
812
|
rmeddis@0
|
813 otherwise % create the stimulus
|
rmeddis@0
|
814 [targetStimulus, errormsg]= ...
|
rmeddis@0
|
815 stimulusCreate(globalStimParams, stimComponents, 0);
|
rmeddis@0
|
816
|
rmeddis@0
|
817 if ~isempty(errormsg) % e.g. limits exceeded
|
rmeddis@0
|
818 errormsg
|
rmeddis@0
|
819 return
|
rmeddis@0
|
820 end
|
rmeddis@0
|
821
|
rmeddis@0
|
822 switch experiment.ear
|
rmeddis@0
|
823 case {'MAPmodel' , 'MAPmodelMultiCh', 'MAPmodelSingleCh', 'MAPmodelListen'}
|
rmeddis@0
|
824 % model requires no calibration correction;
|
rmeddis@0
|
825 % signal is already in Pascals
|
rmeddis@0
|
826 globalStimParams.audioOutCorrection=1;
|
rmeddis@0
|
827 % use only the targetStimulus for the MAP model
|
rmeddis@0
|
828 audio=targetStimulus;
|
rmeddis@0
|
829
|
rmeddis@0
|
830 otherwise % left, right diotic dichotic
|
rmeddis@0
|
831 if stimulusParameters.includeCue
|
rmeddis@0
|
832 audio= [cueStimulus; targetStimulus];
|
rmeddis@0
|
833 else % no cue
|
rmeddis@0
|
834 audio=targetStimulus;
|
rmeddis@0
|
835 end
|
rmeddis@0
|
836 end
|
rmeddis@0
|
837
|
rmeddis@0
|
838 % playtime
|
rmeddis@0
|
839 % order of the cue and test stimuli varies for 2AFC
|
rmeddis@0
|
840 switch experiment.threshEstMethod
|
rmeddis@0
|
841 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@0
|
842 % intervening silence (currently none; masking delay serves this purpose)
|
rmeddis@0
|
843 IAFCinterveningSilence=zeros(round(AFCsilenceDuration/dt),2);
|
rmeddis@0
|
844 if rand>0.5 % put test stimulus first
|
rmeddis@0
|
845 stimulusParameters.testTargetBegins=targetDelay ;
|
rmeddis@0
|
846 stimulusParameters.testTargetEnds= ...
|
rmeddis@0
|
847 targetDelay+targetDuration;
|
rmeddis@0
|
848 stimulusParameters.testNonTargetBegins=...
|
rmeddis@0
|
849 length(cueStimulus)*dt ...
|
rmeddis@0
|
850 + AFCsilenceDuration +targetDelay ;
|
rmeddis@0
|
851 stimulusParameters.testNonTargetEnds=...
|
rmeddis@0
|
852 length(cueStimulus)*dt ...
|
rmeddis@0
|
853 + AFCsilenceDuration+targetDelay+targetDuration;
|
rmeddis@0
|
854
|
rmeddis@0
|
855 set(handles.pushbutton1,'backgroundcolor','r'), drawnow
|
rmeddis@0
|
856 y=audioplayer(targetStimulus, globalStimParams.FS, 24);
|
rmeddis@0
|
857 playblocking(y)
|
rmeddis@0
|
858 set(handles.pushbutton1,'backgroundcolor',...
|
rmeddis@0
|
859 get(0,'defaultUicontrolBackgroundColor')), drawnow
|
rmeddis@0
|
860 y=audioplayer(IAFCinterveningSilence, ...
|
rmeddis@0
|
861 globalStimParams.FS, 24);
|
rmeddis@0
|
862 playblocking(y)
|
rmeddis@0
|
863 set(handles.pushbutton2,'backgroundcolor','r'), drawnow
|
rmeddis@0
|
864 y=audioplayer(cueStimulus, globalStimParams.FS, 24);
|
rmeddis@0
|
865 playblocking(y)
|
rmeddis@0
|
866 set(handles.pushbutton2,'backgroundcolor',...
|
rmeddis@0
|
867 get(0,'defaultUicontrolBackgroundColor')), drawnow
|
rmeddis@0
|
868 withinRuns.stimulusOrder='targetFirst';
|
rmeddis@0
|
869 audio= [targetStimulus; IAFCinterveningSilence; ...
|
rmeddis@0
|
870 cueStimulus]; % for plotting purposes later
|
rmeddis@0
|
871
|
rmeddis@0
|
872 else % put test stimulus second
|
rmeddis@0
|
873 stimulusParameters.testTargetBegins=...
|
rmeddis@0
|
874 length(cueStimulus)*dt ...
|
rmeddis@0
|
875 + AFCsilenceDuration +targetDelay ;
|
rmeddis@0
|
876 stimulusParameters.testTargetEnds=...
|
rmeddis@0
|
877 length(cueStimulus)*dt ...
|
rmeddis@0
|
878 + AFCsilenceDuration+targetDelay+targetDuration;
|
rmeddis@0
|
879 stimulusParameters.testNonTargetBegins=targetDelay ;
|
rmeddis@0
|
880 stimulusParameters.testNonTargetEnds=...
|
rmeddis@0
|
881 targetDelay+targetDuration;
|
rmeddis@0
|
882
|
rmeddis@0
|
883 set(handles.pushbutton1,'backgroundcolor','r'),drawnow
|
rmeddis@0
|
884 y=audioplayer(cueStimulus, globalStimParams.FS, 24);
|
rmeddis@0
|
885 playblocking(y)
|
rmeddis@0
|
886 set(handles.pushbutton1,'backgroundcolor',...
|
rmeddis@0
|
887 get(0,'defaultUicontrolBackgroundColor')), drawnow
|
rmeddis@0
|
888 y=audioplayer(IAFCinterveningSilence, ...
|
rmeddis@0
|
889 globalStimParams.FS, 24);
|
rmeddis@0
|
890 playblocking(y)
|
rmeddis@0
|
891 set(handles.pushbutton2,'backgroundcolor','r'), drawnow
|
rmeddis@0
|
892 y=audioplayer(targetStimulus, globalStimParams.FS, 24);
|
rmeddis@0
|
893 playblocking(y)
|
rmeddis@0
|
894 set(handles.pushbutton2,'backgroundcolor',...
|
rmeddis@0
|
895 get(0,'defaultUicontrolBackgroundColor')), drawnow
|
rmeddis@0
|
896 withinRuns.stimulusOrder='targetSecond';
|
rmeddis@0
|
897 audio= [cueStimulus; IAFCinterveningSilence; ...
|
rmeddis@0
|
898 targetStimulus]; % for plotting purposes later
|
rmeddis@0
|
899 end
|
rmeddis@0
|
900 otherwise % singleInterval
|
rmeddis@0
|
901 if strcmp(experiment.ear,'MAPmodel') ...
|
rmeddis@0
|
902 || strcmp(experiment.ear,'MAPmodelMultiCh') ...
|
rmeddis@0
|
903 || strcmp(experiment.ear,'MAPmodelSingleCh') ...
|
rmeddis@0
|
904 ||strcmp(experiment.ear,'MAPmodelListen')
|
rmeddis@0
|
905 % don't play for MAPmodel
|
rmeddis@0
|
906 switch experiment.ear
|
rmeddis@0
|
907 % except on special request
|
rmeddis@0
|
908 case {'MAPmodelListen'}
|
rmeddis@0
|
909 y=audioplayer(audio, globalStimParams.FS, 24);
|
rmeddis@0
|
910 playblocking(y) % suspends operations until completed
|
rmeddis@0
|
911 end
|
rmeddis@0
|
912 else
|
rmeddis@0
|
913 y=audioplayer(audio, globalStimParams.FS, 24);
|
rmeddis@0
|
914 playblocking(y)
|
rmeddis@0
|
915 end % if experiment.ear
|
rmeddis@0
|
916 end % switch experiment.threshEstMethod
|
rmeddis@0
|
917 end % switch experiment.ear
|
rmeddis@0
|
918
|
rmeddis@0
|
919
|
rmeddis@0
|
920 % switch experiment.ear
|
rmeddis@0
|
921 % case {'MAPmodel', 'MAPmodelListen', 'MAPmodelMultiCh','MAPmodelSingleCh'}
|
rmeddis@0
|
922 % % save audio for later reference or for input to MAP model
|
rmeddis@0
|
923 % wavwrite(audio/max(audio), globalStimParams.FS,32,'stimulus')
|
rmeddis@0
|
924 % end
|
rmeddis@0
|
925
|
rmeddis@0
|
926 % Panel 1
|
rmeddis@0
|
927 % graphical presentation of the stimulus
|
rmeddis@0
|
928 % NB shown *after* the stimulus has been presented
|
rmeddis@0
|
929 axes(expGUIhandles.axes1), cla
|
rmeddis@0
|
930 % plot is HW rectified and plotted as dB re 28e-6
|
rmeddis@0
|
931 % calibration is ignored
|
rmeddis@0
|
932 t=dt:dt:dt*length(audio);
|
rmeddis@0
|
933 plot(t,stimulusParameters.calibrationdB+20*log10((abs(audio)+1e-10)/28e-6))
|
rmeddis@0
|
934 % set(gca,'xtick',[])
|
rmeddis@0
|
935 ylim([-20 100])
|
rmeddis@0
|
936 ylabel('stimulus (dB SPL)')
|
rmeddis@0
|
937 xlim([0 t(end)])
|
rmeddis@0
|
938 grid on
|
rmeddis@0
|
939 header=[betweenRuns.variableName1 ': ' ...
|
rmeddis@0
|
940 num2str(betweenRuns.var1Sequence(betweenRuns.runNumber))];
|
rmeddis@0
|
941 header=[header ' ' num2str(...
|
rmeddis@0
|
942 betweenRuns.var2Sequence(betweenRuns.runNumber)) ':' ...
|
rmeddis@0
|
943 betweenRuns.variableName2 ];
|
rmeddis@0
|
944 title(header)
|
rmeddis@0
|
945
|