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