comparison Copy_of_multithreshold 1.46/nextStimulus.m @ 28:02aa9826efe0

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