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 @ 0:f233164f4c86

History | View | Annotate | Download (35.1 KB)

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
% -------------------------------------- Checks on excessive signal level
318

    
319
% clipping is relevant only for soundcard use (not modelling)
320
switch experiment.ear
321
    case {'left', 'right', 'diotic',...
322
            'dichotic', 'dioticLeft', 'dichoticRight'}
323
        experiment.headphonesUsed=1;
324
    otherwise
325
        experiment.headphonesUsed=0;
326
end
327

    
328
% NB calibration *reduces* the level of the soundCard output
329
switch experiment.ear
330
    case {'left', 'right', 'diotic',...
331
            'dichotic', 'dioticLeft', 'dichoticRight'}
332
        clippingLevel=91+stimulusParameters.calibrationdB;
333
        soundCardMinimum=clippingLevel-20*log10(2^24);
334
    otherwise
335
        clippingLevel=inf;
336
        soundCardMinimum=-inf;
337
end
338

    
339
% Check for extreme WRV values and abort if necessary
340
% WRVname specifies the value that changes from trial to trial
341
withinRuns.forceThreshold=[];
342
switch stimulusParameters.WRVname
343
    % check for extreme values. Note that one of the tones might be switched off
344
    case 'maskerLevel'
345
        upperLevel=stimulusParameters.WRVlimits(2);
346
        lowerLevel=stimulusParameters.WRVlimits(1);
347
        if max(maskerLevel, cueMaskerLevel)> upperLevel
348
            errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ...
349
                ') is too high ***'];
350
            withinRuns.forceThreshold=upperLevel;
351
            withinRuns.forceThreshold=NaN;
352
            return
353
        end
354
        if max(maskerLevel, cueMaskerLevel)< lowerLevel
355
            errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ...
356
                ') is too low ***'];
357
            withinRuns.forceThreshold=lowerLevel;
358
            withinRuns.forceThreshold=NaN;
359
            return
360
        end
361
        
362
        if max(maskerLevel, cueMaskerLevel)> clippingLevel
363
            errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ...
364
                ') is clipping ***'];
365
            withinRuns.forceThreshold=clippingLevel;
366
            withinRuns.forceThreshold=NaN;
367
            return
368
        end
369
                
370
    case 'targetLevel'
371
        upperLevel=stimulusParameters.WRVlimits(2);
372
        lowerLevel=stimulusParameters.WRVlimits(1);
373
        if ~withinRuns.catchTrial
374
            if max(targetLevel, cueTargetLevel)> upperLevel
375
                errormsg=['target level (' ...
376
                    num2str(max(targetLevel, cueTargetLevel)) ...
377
                    ')  is too high ***'];
378
                withinRuns.forceThreshold=upperLevel;
379
            withinRuns.forceThreshold=NaN;
380
                return
381
            end
382
            if max(targetLevel, cueTargetLevel)< lowerLevel
383
                errormsg=['target level (' ...
384
                    num2str(max(targetLevel, cueTargetLevel)) ...
385
                    ')  is too low ***'];
386
                withinRuns.forceThreshold=lowerLevel;
387
            withinRuns.forceThreshold=NaN;
388
                return
389
            end
390
            if max(targetLevel, cueTargetLevel)> clippingLevel
391
                errormsg=['target level (' ...
392
                    num2str(max(targetLevel, cueTargetLevel)) ...
393
                    ')  is clipping ***'];
394
                withinRuns.forceThreshold=upperLevel;
395
            withinRuns.forceThreshold=NaN;
396
                return
397
            end
398
        end    
399
    case 'maskerDuration'
400
        % this is odd! but harmless
401
        if max(maskerDuration, cueMaskerDuration)> ...
402
                stimulusParameters.WRVlimits(2)
403
            errormsg=['maskerDuration (' ...
404
                num2str(max(maskerDuration, cueMaskerDuration))...
405
                ') is too long ***'];
406
            withinRuns.forceThreshold=stimulusParameters.WRVlimits(2);
407
            withinRuns.forceThreshold=NaN;
408
            return
409
        end
410
        
411
        if min(maskerDuration, cueMaskerDuration)...
412
                < stimulusParameters.WRVlimits(1)
413
            errormsg=['maskerDuration (' num2str(maskerLevel) ...
414
                ') too short ***'];
415
            withinRuns.forceThreshold=stimulusParameters.WRVlimits(1);
416
            withinRuns.forceThreshold=NaN;
417
            return
418
        end
419
        
420
        % legacy programming
421
    case 'gapDuration'
422
        if gapDuration<0
423
            errormsg=['gapDuration (' num2str(gapDuration) ...
424
                ') is less than zero  ***'];
425
            return
426
        end
427
        
428
    case 'maskerFrequency'
429
        switch experiment.paradigm
430
            case 'bandwidth'
431
                frequency=maskerFrequency';
432
                if stimulusParameters.WRVstep<0
433
                    lowerLevel=stimulusParameters.targetFrequency;
434
                    upperLevel=stimulusParameters.targetFrequency*2;
435
                else
436
                    lowerLevel=stimulusParameters.targetFrequency/3;
437
                    upperLevel=stimulusParameters.targetFrequency;
438
                end
439
                
440
                if frequency(1)>upperLevel || frequency(1)<lowerLevel
441
                    errormsg=['frequency out of range: ' ...
442
                        num2str(frequency)];
443
                    withinRuns.forceThreshold=frequency;
444
                    return
445
                end
446
            otherwise
447
        end
448
        
449
    case 'maskerRelativeFrequency'
450
        if  maskerRelativeFrequency<stimulusParameters.WRVlimits(1)
451
            errormsg=['masker frequency (' ...
452
                num2str(frequencyDifference) ...
453
                ')  is outside WRV limits ***'];
454
            withinRuns.forceThreshold=stimulusParameters.WRVlimits(1) ;
455
            return
456
        end
457
        if   maskerRelativeFrequency>stimulusParameters.WRVlimits(2)
458
            errormsg=['masker frequency (' ...
459
                num2str(frequencyDifference) ...
460
                ')  is outside WRV limits ***'];
461
            withinRuns.forceThreshold=stimulusParameters.WRVlimits(2) ;
462
            return
463
        end
464
        
465
end
466

    
467
% --------------------------------Ear ----------------------------------
468
globalStimParams.ears='specified';
469
% ear: 1=left, 2=right
470
switch experiment.ear
471
    case 'left'
472
        maskerEar=1;
473
        targetEar=1;
474
    case 'right'
475
        maskerEar=2;
476
        targetEar=2;
477
    case 'dichoticLeft'
478
        maskerEar=2;
479
        targetEar=1;
480
    case 'dichoticRight'
481
        maskerEar=1;
482
        targetEar=2;
483
    case 'diotic'
484
        maskerEar=1;
485
        targetEar=1;
486
        globalStimParams.ears='diotic';
487
    case {'MAPmodel', 'MAPmodelMultiCh', 'MAPmodelSingleCh', 'MAPmodelListen',...
488
            'statsModelLogistic', 'statsModelRareEvent'}
489
        maskerEar=1;
490
        targetEar=1;
491
end
492

    
493
backgroundType=stimulusParameters.backgroundType;
494
switch stimulusParameters.backgroundType
495
    case {'noiseDich', 'pinkNoiseDich'}
496
%     case 'Dich'
497
        % dich means put the background in the ear opposite to the target
498
        backgroundType=backgroundType(1:end-4);
499
        switch targetEar
500
            case 1
501
                backgroundEar=2;
502
            case 2
503
                backgroundEar=1;
504
        end
505
    otherwise
506
%             case {'none','noise', 'pinkNoise', 'TEN','babble'}
507
        backgroundEar=targetEar;
508
end
509

    
510
% ------------------------------- Make Stimulus -------------------
511
% single interval up/down plays cue then target stimulus
512
% 2IFC uses cue stimulus as interval with no target
513
globalStimParams.FS=stimulusParameters.sampleRate;
514
dt=1/stimulusParameters.sampleRate;
515
globalStimParams.dt=dt;
516
stimulusParameters.dt=dt; % for use later
517

    
518
% calibration of sound output
519
correctiondB=stimulusParameters.calibrationdB;
520
globalStimParams.audioOutCorrection=10^(correctiondB/20);
521
% the output will be reduced by this amount in stimulusCreate
522
% i.e.  audio=audio/globalStimParams.audioOutCorrection
523
% A 91 dB level will yield a peak amp of 1 for calibration=0
524
% A 91 dB level will yield a peak amp of 0.4467 for calibration=7
525
% A 98 dB level will yield a peak amp of 1 for calibration=7
526

    
527
precedingSilence=stimulusParameters.stimulusDelay;
528
% all stimuli have 20 ms terminal silence.
529
% this is clearance for modelling late-ringing targets
530
terminalSilence=.03;
531

    
532
% Now compute overall duration of the stimulus
533
% note that all endsilence values are set to -1
534
%  so that they will fill with terminal silence as required to make
535
%  components equal in length
536
% We need to find the longest possible duration
537
duration(1)=precedingSilence+maskerDuration+cueGapDuration...
538
    +targetDuration+terminalSilence;
539
duration(2)=precedingSilence+maskerDuration+gapDuration...
540
    +targetDuration+ terminalSilence;
541
% If the gap is negative we need to ignore it when estimating total length
542
duration(3)=precedingSilence+maskerDuration+ terminalSilence;
543
globalStimParams.overallDuration=max(duration);
544
globalStimParams.nSignalPoints=...
545
    round(globalStimParams.overallDuration/globalStimParams.dt);
546

    
547
%           ----------------------------------------------cue stimulus
548
% cue masker
549
componentNo=1;
550
precedingSilence=stimulusParameters.stimulusDelay;
551
stimComponents(maskerEar,componentNo).type=maskerType;
552
stimComponents(maskerEar,componentNo).toneDuration=cueMaskerDuration;
553
stimComponents(maskerEar,componentNo).frequencies=cueMaskerFrequency;
554
stimComponents(maskerEar,componentNo).amplitudesdB=cueMaskerLevel;
555
stimComponents(maskerEar,componentNo).beginSilence=precedingSilence;
556
stimComponents(maskerEar,componentNo).endSilence=-1;
557
stimComponents(maskerEar,componentNo).AMfrequency=0;
558
stimComponents(maskerEar,componentNo).AMdepth=0;
559
if rampDuration<maskerDuration
560
    % ramps must be shorter than the signal
561
    stimComponents(maskerEar,componentNo).rampOnDur=rampDuration;
562
    stimComponents(maskerEar,componentNo).rampOffDur=rampDuration;
563
else
564
    % or squeeze the ramp in
565
    stimComponents(maskerEar,componentNo).rampOnDur=maskerDuration/2;
566
    stimComponents(maskerEar,componentNo).rampOffDur=maskerDuration/2;
567
end
568
stimComponents(maskerEar,componentNo).phases=...
569
    stimulusParameters.maskerPhase;
570
stimComponents(maskerEar,componentNo).niterations=0;    % for IRN only
571
% stimComponents(targetEar,componentNo)
572

    
573
% cue target
574
componentNo=2;
575
precedingSilence=precedingSilence + maskerDuration+cueGapDuration;
576
stimComponents(targetEar,componentNo).type=targetType;
577
stimComponents(targetEar,componentNo).toneDuration=targetDuration;
578
stimComponents(targetEar,componentNo).frequencies=cueTargetFrequency;
579
stimComponents(targetEar,componentNo).amplitudesdB=cueTargetLevel;
580
stimComponents(targetEar,componentNo).beginSilence=precedingSilence;
581
stimComponents(targetEar,componentNo).endSilence=-1;
582
stimComponents(targetEar,componentNo).AMfrequency=0;
583
stimComponents(targetEar,componentNo).AMdepth=0;
584
if rampDuration<targetDuration
585
    % ramps must be shorter than the signal
586
    stimComponents(targetEar,componentNo).rampOnDur=rampDuration;
587
    stimComponents(targetEar,componentNo).rampOffDur=rampDuration;
588
else
589
    stimComponents(targetEar,componentNo).rampOnDur=0;
590
    stimComponents(targetEar,componentNo).rampOffDur=0;
591
end
592
stimComponents(targetEar,componentNo).phases=...
593
    stimulusParameters.targetPhase;
594
% stimComponents(targetEar,componentNo)
595

    
596
% background same ear as target
597
componentNo=3;
598
stimComponents(backgroundEar,componentNo).type=backgroundType;
599
switch backgroundType
600
    case 'TEN'
601
        fileName=['..' filesep '..' filesep ...
602
            'multithresholdResources' filesep ...
603
            'backgrounds and maskers'...
604
            filesep 'ten.wav'];
605
        [tenNoise, FS]=wavread(fileName);
606
        tenNoise=resample(tenNoise, globalStimParams.FS, FS);
607
        stimComponents(backgroundEar,componentNo).type='file';
608
        stimComponents(backgroundEar,componentNo).stimulus=tenNoise';
609
end
610
stimComponents(backgroundEar,componentNo).toneDuration=...
611
    globalStimParams.overallDuration;
612
stimComponents(backgroundEar,componentNo).amplitudesdB=backgroundLevel;
613
stimComponents(backgroundEar,componentNo).beginSilence=0;
614
stimComponents(backgroundEar,componentNo).endSilence=-1;
615
stimComponents(backgroundEar,componentNo).AMfrequency=0;
616
stimComponents(backgroundEar,componentNo).AMdepth=0;
617
stimComponents(backgroundEar,componentNo).rampOnDur=rampDuration;
618
stimComponents(backgroundEar,componentNo).rampOffDur=rampDuration;
619

    
620
[cueStimulus, errormsg]=...
621
    stimulusCreate(globalStimParams, stimComponents, 0);
622
if ~isempty(errormsg)     % e.g. limits exceeded
623
    errormsg
624
    return
625
end
626

    
627
%               ------------------------------------------ test stimulus
628
% masker
629
componentNo=1;
630
precedingSilence=stimulusParameters.stimulusDelay;
631
stimComponents(maskerEar,componentNo).type=maskerType;
632
stimComponents(maskerEar,componentNo).toneDuration=maskerDuration;
633
stimComponents(maskerEar,componentNo).frequencies=maskerFrequency;
634
stimComponents(maskerEar,componentNo).amplitudesdB=maskerLevel;
635
stimComponents(maskerEar,componentNo).beginSilence=precedingSilence;
636
stimComponents(maskerEar,componentNo).endSilence=-1;
637
stimComponents(maskerEar,componentNo).AMfrequency=0;
638
stimComponents(maskerEar,componentNo).AMdepth=0;
639
if rampDuration<maskerDuration
640
    % ramps must be shorter than the signal
641
    stimComponents(maskerEar,componentNo).rampOnDur=rampDuration;
642
    stimComponents(maskerEar,componentNo).rampOffDur=rampDuration;
643
else
644
    stimComponents(maskerEar,componentNo).rampOnDur=maskerDuration/2;
645
    stimComponents(maskerEar,componentNo).rampOffDur=maskerDuration/2;
646
end
647
stimComponents(maskerEar,componentNo).phases=...
648
    stimulusParameters.maskerPhase;
649
stimComponents(maskerEar,componentNo).niterations=0;    % for IRN only
650

    
651
% target
652
componentNo=2;
653
targetDelay=precedingSilence+ maskerDuration+ gapDuration;
654
stimComponents(targetEar,componentNo).type=targetType;
655
stimComponents(targetEar,componentNo).toneDuration=targetDuration;
656
stimComponents(targetEar,componentNo).frequencies=targetFrequency;
657
stimComponents(targetEar,componentNo).amplitudesdB=targetLevel;
658
stimComponents(targetEar,componentNo).beginSilence=targetDelay;
659
stimComponents(targetEar,componentNo).endSilence=-1;
660
stimComponents(targetEar,componentNo).AMfrequency=0;
661
stimComponents(targetEar,componentNo).AMdepth=0;
662
if rampDuration<targetDuration
663
    % ramps must be shorter than the signal
664
    stimComponents(targetEar,componentNo).rampOnDur=rampDuration;
665
    stimComponents(targetEar,componentNo).rampOffDur=rampDuration;
666
else
667
    stimComponents(targetEar,componentNo).rampOnDur=0;
668
    stimComponents(targetEar,componentNo).rampOffDur=0;
669
end
670
stimComponents(targetEar,componentNo).phases=stimulusParameters.targetPhase;
671
% stimComponents(targetEar,componentNo)
672

    
673
% background same ear as target
674
componentNo=3;
675
stimComponents(backgroundEar,componentNo).type=backgroundType;
676
switch backgroundType
677
    case 'TEN'
678
        fileName=['..' filesep '..' filesep ...
679
            'multithresholdResources' filesep ...
680
            'backgrounds and maskers'...
681
            filesep 'ten.wav'];
682
        [tenNoise, FS]=wavread(fileName);
683

    
684
        tenNoise=resample(tenNoise, globalStimParams.FS, FS);
685
        stimComponents(backgroundEar,componentNo).type='file';
686
        stimComponents(backgroundEar,componentNo).stimulus=tenNoise';
687
end
688
stimComponents(backgroundEar,componentNo).toneDuration=...
689
    globalStimParams.overallDuration;
690
stimComponents(backgroundEar,componentNo).amplitudesdB=backgroundLevel;
691
stimComponents(backgroundEar,componentNo).beginSilence=0;
692
stimComponents(backgroundEar,componentNo).endSilence=-1;
693
stimComponents(backgroundEar,componentNo).rampOnDur=rampDuration;
694
stimComponents(backgroundEar,componentNo).rampOffDur=rampDuration;
695
stimComponents(backgroundEar,componentNo).AMfrequency=0;
696
stimComponents(backgroundEar,componentNo).AMdepth=0;
697

    
698
% timings used when evaluating MAP peripheral model
699
% this is the Slope during which spikes are counted
700
switch experiment.paradigm
701
    case 'gapDetection'
702
        % gap is the 'target' in this case
703
        stimulusParameters.testTargetBegins=...
704
            stimulusParameters.stimulusDelay...
705
            +stimulusParameters.maskerDuration;
706
        stimulusParameters.testTargetEnds=...
707
            stimulusParameters.testTargetBegins+withinRuns.variableValue;
708
%     case 'SRT'
709
%         set(handles.editdigitInput,'visible','off')
710
    otherwise
711
        stimulusParameters.testTargetBegins=targetDelay;
712
        stimulusParameters.testTargetEnds=targetDelay+targetDuration;
713
end
714

    
715
% ------------------------------------------------------------- play!
716
% Create and play stimulus (as required by different paradigms)
717
switch experiment.ear
718
    case {'statsModelLogistic', 'statsModelRareEvent'}
719
        audio=[0;0];            % no need to compute stimulus
720
        
721
    otherwise                   % create the stimulus
722
        [targetStimulus, errormsg]= ...
723
            stimulusCreate(globalStimParams, stimComponents, 0);
724
        
725
        if ~isempty(errormsg)   % e.g. limits exceeded
726
            errormsg
727
            return
728
        end
729
        
730
        switch experiment.ear
731
            case {'MAPmodel' , 'MAPmodelMultiCh', 'MAPmodelSingleCh', 'MAPmodelListen'}
732
                % model requires no calibration correction;
733
                %  signal is already in Pascals
734
                globalStimParams.audioOutCorrection=1;
735
                % use only the targetStimulus for the MAP model
736
                audio=targetStimulus;
737
                
738
            otherwise           % left, right diotic dichotic
739
                if stimulusParameters.includeCue
740
                    audio= [cueStimulus;  targetStimulus];
741
                else            % no cue
742
                    audio=targetStimulus;
743
                end
744
        end
745
        
746
        % playtime
747
        % order of the cue and test stimuli varies for 2AFC
748
        switch experiment.threshEstMethod
749
            case {'2I2AFC++', '2I2AFC+++'}
750
                % intervening silence (currently none; masking delay serves this purpose)
751
                IAFCinterveningSilence=zeros(round(AFCsilenceDuration/dt),2);
752
                if rand>0.5				% put test stimulus first
753
                    stimulusParameters.testTargetBegins=targetDelay ;
754
                    stimulusParameters.testTargetEnds= ...
755
                        targetDelay+targetDuration;
756
                    stimulusParameters.testNonTargetBegins=...
757
                        length(cueStimulus)*dt ...
758
                        + AFCsilenceDuration +targetDelay ;
759
                    stimulusParameters.testNonTargetEnds=...
760
                        length(cueStimulus)*dt ...
761
                        + AFCsilenceDuration+targetDelay+targetDuration;
762
                    
763
                    set(handles.pushbutton1,'backgroundcolor','r'), drawnow
764
                    y=audioplayer(targetStimulus, globalStimParams.FS, 24);
765
                    playblocking(y)
766
                    set(handles.pushbutton1,'backgroundcolor',...
767
                        get(0,'defaultUicontrolBackgroundColor')), drawnow
768
                    y=audioplayer(IAFCinterveningSilence, ...
769
                        globalStimParams.FS, 24);
770
                    playblocking(y)
771
                    set(handles.pushbutton2,'backgroundcolor','r'), drawnow
772
                    y=audioplayer(cueStimulus, globalStimParams.FS, 24);
773
                    playblocking(y)
774
                    set(handles.pushbutton2,'backgroundcolor',...
775
                        get(0,'defaultUicontrolBackgroundColor')), drawnow
776
                    withinRuns.stimulusOrder='targetFirst';
777
                    audio= [targetStimulus; IAFCinterveningSilence; ...
778
                        cueStimulus];   % for plotting purposes later
779
                    
780
                else					% put test stimulus second
781
                    stimulusParameters.testTargetBegins=...
782
                        length(cueStimulus)*dt ...
783
                        + AFCsilenceDuration +targetDelay ;
784
                    stimulusParameters.testTargetEnds=...
785
                        length(cueStimulus)*dt ...
786
                        + AFCsilenceDuration+targetDelay+targetDuration;
787
                    stimulusParameters.testNonTargetBegins=targetDelay ;
788
                    stimulusParameters.testNonTargetEnds=...
789
                        targetDelay+targetDuration;
790
                    
791
                    set(handles.pushbutton1,'backgroundcolor','r'),drawnow
792
                    y=audioplayer(cueStimulus, globalStimParams.FS, 24);
793
                    playblocking(y)
794
                    set(handles.pushbutton1,'backgroundcolor',...
795
                        get(0,'defaultUicontrolBackgroundColor')), drawnow
796
                    y=audioplayer(IAFCinterveningSilence, ...
797
                        globalStimParams.FS, 24);
798
                    playblocking(y)
799
                    set(handles.pushbutton2,'backgroundcolor','r'), drawnow
800
                    y=audioplayer(targetStimulus, globalStimParams.FS, 24);
801
                    playblocking(y)
802
                    set(handles.pushbutton2,'backgroundcolor',...
803
                        get(0,'defaultUicontrolBackgroundColor')), drawnow
804
                    withinRuns.stimulusOrder='targetSecond';
805
                    audio= [cueStimulus; IAFCinterveningSilence; ...
806
                        targetStimulus];    % for plotting purposes later
807
                end
808
            otherwise                       % singleInterval
809
                if strcmp(experiment.ear,'MAPmodel') ...
810
                        || strcmp(experiment.ear,'MAPmodelMultiCh') ...
811
                        || strcmp(experiment.ear,'MAPmodelSingleCh') ...
812
                        ||strcmp(experiment.ear,'MAPmodelListen')
813
                    % don't play for MAPmodel
814
                    switch experiment.ear
815
                        % except on special request
816
                        case {'MAPmodelListen'}
817
                            y=audioplayer(audio, globalStimParams.FS, 24);
818
                            playblocking(y) % suspends operations until completed
819
                    end
820
                else
821
                    y=audioplayer(audio, globalStimParams.FS, 24);
822
                    playblocking(y)
823
                end	  %   if experiment.ear
824
        end	% switch experiment.threshEstMethod
825
end % switch experiment.ear
826

    
827

    
828
% switch experiment.ear
829
%     case	{'MAPmodel', 'MAPmodelListen',  'MAPmodelMultiCh','MAPmodelSingleCh'}
830
%         % save audio for later reference or for input to MAP model
831
%         wavwrite(audio/max(audio), globalStimParams.FS,32,'stimulus')
832
% end
833

    
834
% Panel 1
835
% graphical presentation of the stimulus
836
% NB shown *after* the stimulus has been presented
837
axes(expGUIhandles.axes1), cla
838
% plot is HW rectified and plotted as dB re 28e-6
839
% calibration is ignored
840
t=dt:dt:dt*length(audio);
841
plot(t,stimulusParameters.calibrationdB+20*log10((abs(audio)+1e-10)/28e-6))
842
% set(gca,'xtick',[])
843
ylim([-20 100])
844
ylabel('stimulus (dB SPL)')
845
xlim([0 t(end)])
846
grid on
847
header=[betweenRuns.variableName1  ': ' ...
848
    num2str(betweenRuns.var1Sequence(betweenRuns.runNumber))];
849
header=[header '      ' num2str(...
850
    betweenRuns.var2Sequence(betweenRuns.runNumber)) ':' ...
851
    betweenRuns.variableName2 ];
852
title(header)
853