To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at git://github.com/rmeddis/MAP.git .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Revision:

root / multithreshold 1.46 / nextStimulus.m @ 38:c2204b18f4a2

History | View | Annotate | Download (38.5 KB)

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