view multithreshold 1.46/nextStimulus.m @ 38:c2204b18f4a2 tip

End nov big change
author Ray Meddis <rmeddis@essex.ac.uk>
date Mon, 28 Nov 2011 13:34:28 +0000
parents 3ea506487b3b
children
line wrap: on
line source
function errormsg=nextStimulus(handles)
% Handles everything concerned with the stimulus presentation
%  called from startNewRun in subjGUI

global experiment stimulusParameters withinRuns  betweenRuns
experiment.status='presentingStimulus';
errormsg='';

% interrupt by 'stop' button
% if experiment.stop
%     disp('******** experiment manually stopped  *****************')
%     experiment.status= 'waitingForStart';
%     errormsg='manually stopped';
%     addToMsg(errormsg,1)
%     return
% end

% -----------------------------------------choose catch trials at random
% catch trials are for subject threshold measurements only
% this is the only place where withinRuns.catchTrial is set
if experiment.allowCatchTrials
    if withinRuns.trialNumber==1;
        % first trial is never a catch trial
        withinRuns.catchTrial=0;
        withinRuns.catchTrialCount=0;   % reset count on first trial
    elseif withinRuns.trialNumber==2 ...
            && withinRuns.catchTrialCount==0
        % second trial is always a catch trial
        withinRuns.catchTrial=1;
        withinRuns.catchTrialCount=1;   % this must be the first
    elseif withinRuns.thisIsRepeatTrial
        % for requested repeats do not change catch trial status
        withinRuns.thisIsRepeatTrial=0; % reset toggle
    else
        % choose whether or not to have a catch trial
        R=rand;
        if R<stimulusParameters.catchTrialRate
            % catch trial
            withinRuns.catchTrial=1;
            addToMsg('Catch Trial',1)
            withinRuns.catchTrialCount=withinRuns.catchTrialCount+1;
        else
            % not a catch trial
            withinRuns.catchTrial=0;
        end
    end
else
    % no catch trials for statistical evaluations or 2AIFC or (poss) MAP
    withinRuns.catchTrial=0;
end

%------------ during stimulus presentation show appropriate button images
switch experiment.ear
    case {'statsModelLogistic', 'statsModelRareEvent',...
            'MAPmodel', 'MAPmodelMultiCh', 'MAPmodelSingleCh'}
        % no buttons shown
    otherwise
        switch experiment.threshEstMethod
            case {'2I2AFC++', '2I2AFC+++'}
                %Except for 2I2AFC
                % For 2I2AFC the buttons on the screen ab initio
                set(handles.frame1,'visible','off')
                set(handles.pushbuttonGO,'visible','off')
                set(handles.pushbuttoNotSure,'visible','off')
                set(handles.pushbuttonWrongButton,'visible','off')
                set(handles.pushbutton3,'visible','off')
                set(handles.pushbutton0,'visible','off')
                set(handles.pushbutton1,'visible','on')
                set(handles.pushbutton2,'visible','on')
                drawnow
            otherwise
                % i.e. single interval/ maxLikelihood
                set(handles.frame1,'backgroundColor','w')
                set(handles.frame1,'visible','off')
                set(handles.pushbuttoNotSure,'visible','off')
                set(handles.pushbuttonWrongButton,'visible','off')
                set(handles.pushbutton3,'visible','off')
                set(handles.pushbutton2,'visible','off')
                set(handles.pushbutton1,'visible','off')
                set(handles.pushbutton0,'visible','off')
                pause(.1)
        end
end

set(handles.textMSG,'BackgroundColor','w', 'ForegroundColor', 'b')

% Now the serious business of crafting and presenting the stimulus
errormsg= stimulusMakeAndPlay (handles);

if ~isempty(errormsg)
    % e.g. clipping. subjGUI will service the error
    return
end

% after playing the stimulus, reset the subjectGUI
switch experiment.ear
    case {'statsModelLogistic', 'statsModelRareEvent',...
            'MAPmodel', 'MAPmodelMultiCh', 'MAPmodelSingleCh'}
        % no changes required if model used
        % NB these changes do occur is 'MAPmodelListen' is selected
    otherwise
        switch experiment.threshEstMethod
            case {'2I2AFC++', '2I2AFC+++'}
                % buttons already visible
            otherwise
                % single interval now make buttons visible
                set(handles.frame1,'visible','on')
                set(handles.pushbuttoNotSure,'visible','on')
                % set(handles.pushbuttonWrongButton,'visible','on')
                set(handles.pushbutton0,'visible','on')
                set(handles.pushbutton1,'visible','on')
                set(handles.pushbutton2,'visible','on')
                set(handles.pushbutton3,'visible','on')
        end
end

switch experiment.paradigm
    case 'SRT'
        set(handles.frame1,'backgroundColor','w')
        set(handles.frame1,'visible','off')
        set(handles.pushbuttoNotSure,'visible','off')
        set(handles.pushbuttonWrongButton,'visible','off')
        set(handles.pushbutton3,'visible','off')
        set(handles.pushbutton2,'visible','off')
        set(handles.pushbutton1,'visible','off')
        set(handles.pushbutton0,'visible','off')
        set(handles.editdigitInput,'visible','on')
        set(handles.editdigitInput,'string',[])
        pause(.2)
        uicontrol(handles.editdigitInput)
        
    otherwise
        set(handles.editdigitInput,'visible','off')
end


experiment.status='waitingForResponse';
% home again

% ------------------------------------------------------------------------------------------stimulusMakeAndPlay
function errormsg=stimulusMakeAndPlay (handles)
global experiment stimulusParameters betweenRuns withinRuns expGUIhandles  audio
% creates the stimulus and plays it; there are two stimuli; cue and test
%  called from nextStimulus

errormsg='';

% first post the subjects instructions on subjGUI
set(handles.textMSG,'string', stimulusParameters.subjectText)

% select the new levels of the between runs variables
thisRunNumber=betweenRuns.runNumber;
cmd=(['stimulusParameters.' betweenRuns.variableName1 '= ' ...
    num2str(betweenRuns.var1Sequence(thisRunNumber)) ';']);
% e.g.  stimulusParameters.targetFrequency= 1000;
eval(cmd);

cmd=(['stimulusParameters.' betweenRuns.variableName2 '= ' ...
    num2str(betweenRuns.var2Sequence(thisRunNumber)) ';']);
% e.g.  stimulusParameters.targetDuration= 0.1;
eval(cmd);

% When variableList2 is 'targetFrequency' targetLevel may vary between runs 
% If so, it is changed at the end of each variableList1.
if strcmp(betweenRuns.variableName2, 'targetFrequency') && ...
        length(stimulusParameters.targetLevels)>1
    switch experiment.paradigm
        case {'trainingIFMC', 'TMC','TMC_16ms', 'TMC - ELP', 'IFMC','IFMC_8ms','IFMC_16ms'}
            idx=floor(thisRunNumber/length(betweenRuns.variableList1)-0.01)+1;
            cmd=(['stimulusParameters.targetLevel = ' ...
                num2str(stimulusParameters.targetLevels(idx)) ';']);
            eval(cmd);
            if withinRuns.trialNumber==1
                disp(['targetLevel=' num2str(stimulusParameters.targetLevel)])
            end
    end
end


% for more readable code use shorter variable names;
% NB these may change below; these are only the starting values

targetType=        stimulusParameters.targetType;
targetDuration=    stimulusParameters.targetDuration;
targetLevel=       stimulusParameters.targetLevel;
targetFrequency=   stimulusParameters.targetFrequency;

maskerType=        stimulusParameters.maskerType;
maskerDuration=    stimulusParameters.maskerDuration;
maskerLevel=       stimulusParameters.maskerLevel;
maskerRelativeFrequency=  stimulusParameters.maskerRelativeFrequency;
maskerFrequency=   maskerRelativeFrequency*targetFrequency;

gapDuration=       stimulusParameters.gapDuration;

rampDuration=      stimulusParameters.rampDuration;
AFCsilenceDuration=stimulusParameters.AFCsilenceDuration; % 2I2AFC gap
backgroundLevel=   stimulusParameters.backgroundLevel;

% Set level of within runs variable
% this is the first change to one of the values shown above
cmd=[stimulusParameters.WRVname '= withinRuns.variableValue;' ];
% e.g.: maskerLevel= withinRuns.variableValue;
eval(cmd);

% cue and test stimuli are identical except for a single difference
% depending on the paradigm
cueTestDifference= stimulusParameters.cueTestDifference;
%  cue characteristics before adding cue differences
cueTargetLevel=targetLevel;
cueMaskerFrequency=maskerFrequency;
cueMaskerDuration=maskerDuration;
cueMaskerLevel=maskerLevel;
cueTargetFrequency=targetFrequency;
cueGapDuration=gapDuration;

% ----------------------------paradigm sensitive cue and masker settings
% switch off unwanted components and base cue on target values
% for catch trials switch off the target

% --- set cueTarget level according to assessment method
% cue-test difference applies only with singleInterval
switch experiment.threshEstMethod
    case {'2I2AFC++', '2I2AFC+++'}
        % For 2IFC the cue stimulus (masker + probe) is the 'no' window
        % and the target stimulus (masker+probe) is the 'yes' window
        % the order of presentation is decided at the last minute.
        cueTargetLevel=-100;    % the target is never in the 'no' window
        cueMaskerLevel=maskerLevel; % masker level is the same in both
    otherwise
        % 'single interval' or max likelihood
        switch experiment.paradigm
            % cue target is more audible
            case {'training','absThreshold', 'absThreshold_8',  ...
                    'TENtest', 'threshold_duration','discomfort',...
                    'overShoot','overShootB','overShootMB1', ...
                    'overShootMB2', 'OHIO','OHIOabs','OHIOspect'...
                    'OHIOrand', 'OHIOtemp', 'OHIOspectemp'}
                cueTargetLevel=targetLevel+cueTestDifference;
                
            case {'forwardMasking','forwardMaskingD','trainingIFMC', ...
                    'TMC','TMC_16ms', 'TMC - ELP', 'IFMC','IFMC_8ms', ...
                    'FMreProbe'}
                % cue masker is weaker to make target more audible
                cueMaskerLevel=maskerLevel-cueTestDifference;
        end
end

% thresholds (in dB SPL) of the single tone with 12 frequencies:
%    1   2    3     4    5     6     7     8     9     10     11    12
% 494, 663, 870, 1125, 1442, 1838, 2338, 2957, 3725, 4689, 5866, 7334

% 2. ‘OHIOtemp’ is for measuring thresholds for temporally integrated
% combinations of 2, 4, 8, and 12 tones presented simultaneously.
% In our experiment, we used 4680Hz frequency.

% 3. ‘OHIOspec’ is for measuring thresholds for spectrally integrated
% combinations of 2(7335 and 5866Hz), 4(7334, 5866, 4680, and 3725Hz),
% 8(7334, 5866, 4680, 3725, 2957, 2338, 1838, and
% 1442Hz), and
% 12(all 12 frequencies) tones presented simultaneously.

% 4. ‘OHIOspectemp’ is for measuring thresholds for patterned signals
% differing in both the spectral and temporal domains.
% The frequency conditions are the same as that of ‘OHIOspec’.

% 5. ‘OHIOrand’ is for measuring thresholds for spectrotemporally varying
% signals with random frequency presentation.

switch experiment.paradigm(1:3)
    case 'OHI'
        targetType='OHIO';
        OHIOtype=experiment.paradigm;
        % 1. ‘OHIOabs’ paradigm is a baseline procedure for measuring absolute

        nTones=betweenRuns.var1Sequence(betweenRuns.runNumber);
        allFreqs=[494, 663, 870, 1125, 1442, 1838, 2338, 2957, 3725, 4689, 5866, 7334];
        toneLevelBoost= ...
            [1	0	0	1	1	4	8	12	12	14	17	19 ];


        % for nTones=nTonesList
        switch experiment.paradigm
            %         case ' OHIOabs'
            %             % one tone frequency at a time
            %             stim.frequencies=allFreqs(1);
            %             stim.amplitudesdB=0;

            case 'OHIOrand'
                % chose nTones frequencies at random
                x=rand(1,12);
                [sorted idx]=sort(x);
                cueTargetFrequency=allFreqs(idx(1:nTones));
                cueTargetLevel=toneLevelBoost(idx)+...
                    targetLevel + cueTestDifference;
                targetFrequency=allFreqs(idx(1:nTones));
                targetLevel=targetLevel + toneLevelBoost(idx);

            case 'OHIOtemp'
                % 4680 Hz repeated nTones times
                cueTargetFrequency=4680*ones(1,nTones);
                cueTargetLevel=repmat(toneLevelBoost(10),1,nTones)+...
                    targetLevel + cueTestDifference;
                targetFrequency=4680*ones(1,nTones);
                targetLevel= targetLevel+repmat(toneLevelBoost(10),1,nTones);

            case {'OHIOspect',  'OHIOspectemp'}
                % nTones frequencies either simulataneously or sequentially
                switch nTones
                    case 2
                        cueTargetFrequency=[7335 5866];
                        targetFrequency=[7335 5866];
                        idx=[12 11];
                        cueTargetLevel=targetLevel + toneLevelBoost(idx)+cueTestDifference;
                        targetLevel=targetLevel + toneLevelBoost(idx);
                    case 4
                        cueTargetFrequency=[7334, 5866, 4680, 3725];
                        targetFrequency=[7334, 5866, 4680, 3725];
                        idx=[12:-1:9 ];
                        cueTargetLevel=targetLevel + toneLevelBoost(idx)+cueTestDifference;
                        targetLevel=targetLevel + toneLevelBoost(idx);
                    case 8
                        cueTargetFrequency=...
                            [7334, 5866, 4680, 3725, 2957, 2338, 1838, 1442];
                        targetFrequency=...
                            [7334, 5866, 4680, 3725, 2957, 2338, 1838, 1442];
                        idx=[12:-1:5 ];
                        cueTargetLevel=targetLevel + toneLevelBoost(idx)+cueTestDifference;
                        targetLevel=targetLevel + toneLevelBoost(idx);
                    case 12
                        cueTargetFrequency=allFreqs;
                        targetFrequency=allFreqs;
                        cueTargetLevel=targetLevel + toneLevelBoost(1:12)+cueTestDifference;
                        targetLevel=targetLevel + toneLevelBoost(1:12);
                end
        end

    otherwise
        OHIOtype='none';
end

switch experiment.paradigm(1:3)
    case 'OHI'

        switch experiment.threshEstMethod
            case {'2I2AFC++', '2I2AFC+++'}
                % the cue stimulus (masker + probe) is the 'no' window
                % the target stimulus (masker+probe) is the 'yes' window
                % the order of presentation is decided at the last minute.
                cueTargetLevel=-100; 
        end


        switch experiment.paradigm
            case {'OHIOabs', 'OHIOspect'}
                OHIOtoneDuration=.02+stimulusParameters.stimulusDelay;
                globalStimParams.overallDuration=OHIOtoneDuration;
            otherwise
                OHIOtoneDuration=nTones*0.02+stimulusParameters.stimulusDelay;
                globalStimParams.overallDuration=OHIOtoneDuration;
        end
end

% ----------------------------- catch trial
if withinRuns.catchTrial
    targetLevel=-100;	% no target
end

% ----------------------------- calibration of sound output
% seperate calibration for each frequency to match headphones
calibrationCorrectiondB=stimulusParameters.calibrationdB;
if calibrationCorrectiondB<-50
    if maskerFrequency==targetFrequency
        load 'calibrationFile'  % calibrationFrequency calibrationAttenutation
        idx=find(calibrationFrequency==targetFrequency);
        if isempty(idx)
            error('Calibration by file; frequency not found')
        else
            calibrationCorrectiondB=calibrationAttenutation(idx)
        end
    else
        error('calibration by file requested but masker frequency is not the same as target')
    end
end


% -------------------------------------- Checks on excessive signal level

% clipping is relevant only for soundcard use (not modelling)
switch experiment.ear
    case {'left', 'right', 'diotic',...
            'dichotic', 'dioticLeft', 'dichoticRight'}
        experiment.headphonesUsed=1;
    otherwise
        experiment.headphonesUsed=0;
end

% NB calibration *reduces* the level of the soundCard output
switch experiment.ear
    case {'left', 'right', 'diotic',...
            'dichotic', 'dioticLeft', 'dichoticRight'}
        clippingLevel=91+calibrationCorrectiondB;
        soundCardMinimum=clippingLevel-20*log10(2^24);
    otherwise
        clippingLevel=inf;
        soundCardMinimum=-inf;
end

% Check for extreme WRV values and abort if necessary
% WRVname specifies the value that changes from trial to trial
withinRuns.forceThreshold=[];
switch stimulusParameters.WRVname
    % check for extreme values. Note that one of the tones might be switched off
    case 'maskerLevel'
        upperLevel=stimulusParameters.WRVlimits(2);
        lowerLevel=stimulusParameters.WRVlimits(1);
        if max(maskerLevel, cueMaskerLevel)> upperLevel
            errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ...
                ') is too high ***'];
            withinRuns.forceThreshold=upperLevel;
            withinRuns.forceThreshold=NaN;
            return
        end
        if max(maskerLevel, cueMaskerLevel)< lowerLevel
            errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ...
                ') is too low ***'];
            withinRuns.forceThreshold=lowerLevel;
            withinRuns.forceThreshold=NaN;
            return
        end
        
        if max(maskerLevel, cueMaskerLevel)> clippingLevel
            errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ...
                ') is clipping ***'];
            withinRuns.forceThreshold=clippingLevel;
            withinRuns.forceThreshold=NaN;
            return
        end
        
    case 'targetLevel'
        upperLevel=stimulusParameters.WRVlimits(2);
        lowerLevel=stimulusParameters.WRVlimits(1);
        if ~withinRuns.catchTrial
            if max(targetLevel, cueTargetLevel)> upperLevel
                errormsg=['target level (' ...
                    num2str(max(targetLevel, cueTargetLevel)) ...
                    ')  is too high ***'];
                withinRuns.forceThreshold=upperLevel;
                withinRuns.forceThreshold=NaN;
                return
            end
            if max(targetLevel, cueTargetLevel)< lowerLevel
                errormsg=['target level (' ...
                    num2str(max(targetLevel, cueTargetLevel)) ...
                    ')  is too low ***'];
                withinRuns.forceThreshold=lowerLevel;
                withinRuns.forceThreshold=NaN;
                return
            end
            if max(targetLevel, cueTargetLevel)> clippingLevel
                errormsg=['target level (' ...
                    num2str(max(targetLevel, cueTargetLevel)) ...
                    ')  is clipping ***'];
                withinRuns.forceThreshold=upperLevel;
                withinRuns.forceThreshold=NaN;
                return
            end
        end
    case 'maskerDuration'
        % this is odd! but harmless
        if max(maskerDuration, cueMaskerDuration)> ...
                stimulusParameters.WRVlimits(2)
            errormsg=['maskerDuration (' ...
                num2str(max(maskerDuration, cueMaskerDuration))...
                ') is too long ***'];
            withinRuns.forceThreshold=stimulusParameters.WRVlimits(2);
            withinRuns.forceThreshold=NaN;
            return
        end
        
        if min(maskerDuration, cueMaskerDuration)...
                < stimulusParameters.WRVlimits(1)
            errormsg=['maskerDuration (' num2str(maskerLevel) ...
                ') too short ***'];
            withinRuns.forceThreshold=stimulusParameters.WRVlimits(1);
            withinRuns.forceThreshold=NaN;
            return
        end
        
    case 'gapDuration'
        % legacy programming
        if gapDuration<0
            errormsg=['gapDuration (' num2str(gapDuration) ...
                ') is less than zero  ***'];
            return
        end
        
    case 'maskerFrequency'
        switch experiment.paradigm
            case 'bandwidth'
                frequency=maskerFrequency';
                if stimulusParameters.WRVstep<0
                    lowerLevel=stimulusParameters.targetFrequency;
                    upperLevel=stimulusParameters.targetFrequency*2;
                else
                    lowerLevel=stimulusParameters.targetFrequency/3;
                    upperLevel=stimulusParameters.targetFrequency;
                end
                
                if frequency(1)>upperLevel || frequency(1)<lowerLevel
                    errormsg=['frequency out of range: ' ...
                        num2str(frequency)];
                    withinRuns.forceThreshold=frequency;
                    return
                end
            otherwise
        end
        
    case 'maskerRelativeFrequency'
        if  maskerRelativeFrequency<stimulusParameters.WRVlimits(1)
            errormsg=['masker frequency (' ...
                num2str(frequencyDifference) ...
                ')  is outside WRV limits ***'];
            withinRuns.forceThreshold=stimulusParameters.WRVlimits(1) ;
            return
        end
        if   maskerRelativeFrequency>stimulusParameters.WRVlimits(2)
            errormsg=['masker frequency (' ...
                num2str(frequencyDifference) ...
                ')  is outside WRV limits ***'];
            withinRuns.forceThreshold=stimulusParameters.WRVlimits(2) ;
            return
        end
        
end

% --------------------------------Ear ----------------------------------
globalStimParams.ears='specified';
% ear: 1=left, 2=right
switch experiment.ear
    case 'left'
        maskerEar=1;
        targetEar=1;
    case 'right'
        maskerEar=2;
        targetEar=2;
    case 'dichoticLeft'
        maskerEar=2;
        targetEar=1;
    case 'dichoticRight'
        maskerEar=1;
        targetEar=2;
    case 'diotic'
        maskerEar=1;
        targetEar=1;
        globalStimParams.ears='diotic';
    case {'MAPmodel', 'MAPmodelMultiCh', 'MAPmodelSingleCh', 'MAPmodelListen',...
            'statsModelLogistic', 'statsModelRareEvent'}
        maskerEar=1;
        targetEar=1;
end

backgroundType=stimulusParameters.backgroundType;
switch stimulusParameters.backgroundType
    case {'noiseDich', 'pinkNoiseDich'}
        %     case 'Dich'
        % dich means put the background in the ear opposite to the target
        backgroundType=backgroundType(1:end-4);
        switch targetEar
            case 1
                backgroundEar=2;
            case 2
                backgroundEar=1;
        end
    otherwise
        %             case {'none','noise', 'pinkNoise', 'TEN','babble'}
        backgroundEar=targetEar;
end

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



globalStimParams.audioOutCorrection=10^(calibrationCorrectiondB/20);
% the output will be reduced by this amount in stimulusCreate
% i.e.  audio=audio/globalStimParams.audioOutCorrection
% A 91 dB level will yield a peak amp of 1 for calibration=0
% A 91 dB level will yield a peak amp of 0.4467 for calibration=7
% A 98 dB level will yield a peak amp of 1 for calibration=7

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

% Now compute overall duration of the stimulus
% note that all endsilence values are set to -1
%  so that they will fill with terminal silence as required to make
%  components equal in length
% We need to find the longest possible duration
duration(1)=precedingSilence+maskerDuration+cueGapDuration...
    +targetDuration+terminalSilence;
duration(2)=precedingSilence+maskerDuration+gapDuration...
    +targetDuration+ terminalSilence;
% If the gap is negative we need to ignore it when estimating total length
duration(3)=precedingSilence+maskerDuration+ terminalSilence;
globalStimParams.overallDuration=max(duration);
globalStimParams.nSignalPoints=...
    round(globalStimParams.overallDuration*globalStimParams.FS);

% special case
switch experiment.paradigm(1:3)
    case 'OHI'
        switch experiment.paradigm
            case {'OHIOabs', 'OHIOspect'}
                OHIOtoneDuration=.02+stimulusParameters.stimulusDelay;
                globalStimParams.overallDuration=OHIOtoneDuration;
            otherwise
                OHIOtoneDuration=nTones*0.02+stimulusParameters.stimulusDelay;
                globalStimParams.overallDuration=OHIOtoneDuration;
        end
end


%           ----------------------------------------------cue stimulus
% cue masker
componentNo=1;
precedingSilence=stimulusParameters.stimulusDelay;
stimComponents(maskerEar,componentNo).type=maskerType;
stimComponents(maskerEar,componentNo).toneDuration=cueMaskerDuration;
stimComponents(maskerEar,componentNo).frequencies=cueMaskerFrequency;
stimComponents(maskerEar,componentNo).amplitudesdB=cueMaskerLevel;
stimComponents(maskerEar,componentNo).beginSilence=precedingSilence;
stimComponents(maskerEar,componentNo).endSilence=-1;
stimComponents(maskerEar,componentNo).AMfrequency=0;
stimComponents(maskerEar,componentNo).AMdepth=0;
if rampDuration<maskerDuration
    % ramps must be shorter than the signal
    stimComponents(maskerEar,componentNo).rampOnDur=rampDuration;
    stimComponents(maskerEar,componentNo).rampOffDur=rampDuration;
else
    % or squeeze the ramp in
    stimComponents(maskerEar,componentNo).rampOnDur=maskerDuration/2;
    stimComponents(maskerEar,componentNo).rampOffDur=maskerDuration/2;
end
stimComponents(maskerEar,componentNo).phases=...
    stimulusParameters.maskerPhase;
stimComponents(maskerEar,componentNo).niterations=0;    % for IRN only
% stimComponents(targetEar,componentNo)

% cue target
componentNo=2;
precedingSilence=precedingSilence + maskerDuration+cueGapDuration;
stimComponents(targetEar,componentNo).type=targetType;
stimComponents(targetEar,componentNo).OHIOtype=OHIOtype;
stimComponents(targetEar,componentNo).toneDuration=targetDuration;
stimComponents(targetEar,componentNo).frequencies=cueTargetFrequency;
stimComponents(targetEar,componentNo).amplitudesdB=cueTargetLevel;
stimComponents(targetEar,componentNo).beginSilence=precedingSilence;
stimComponents(targetEar,componentNo).endSilence=-1;
stimComponents(targetEar,componentNo).AMfrequency=0;
stimComponents(targetEar,componentNo).AMdepth=0;
if rampDuration<targetDuration
    % ramps must be shorter than the signal
    stimComponents(targetEar,componentNo).rampOnDur=rampDuration;
    stimComponents(targetEar,componentNo).rampOffDur=rampDuration;
else
    stimComponents(targetEar,componentNo).rampOnDur=0;
    stimComponents(targetEar,componentNo).rampOffDur=0;
end
stimComponents(targetEar,componentNo).phases=...
    stimulusParameters.targetPhase;
% stimComponents(targetEar,componentNo)

% background same ear as target
componentNo=3;
stimComponents(backgroundEar,componentNo).type=backgroundType;
switch backgroundType
    case 'TEN'
        fileName=['..' filesep '..' filesep ...
            'multithresholdResources' filesep ...
            'backgrounds and maskers'...
            filesep 'ten.wav'];
        [tenNoise, FS]=wavread(fileName);
        tenNoise=resample(tenNoise, globalStimParams.FS, FS);
        stimComponents(backgroundEar,componentNo).type='file';
        stimComponents(backgroundEar,componentNo).stimulus=tenNoise';
end
stimComponents(backgroundEar,componentNo).toneDuration=...
    globalStimParams.overallDuration;
stimComponents(backgroundEar,componentNo).amplitudesdB=backgroundLevel;
stimComponents(backgroundEar,componentNo).beginSilence=0;
stimComponents(backgroundEar,componentNo).endSilence=-1;
stimComponents(backgroundEar,componentNo).AMfrequency=0;
stimComponents(backgroundEar,componentNo).AMdepth=0;
stimComponents(backgroundEar,componentNo).rampOnDur=rampDuration;
stimComponents(backgroundEar,componentNo).rampOffDur=rampDuration;

[cueStimulus, errormsg]=...
    stimulusCreate(globalStimParams, stimComponents, 0);
if ~isempty(errormsg)     % e.g. limits exceeded
    errormsg
    return
end

%               ------------------------------------------ test stimulus
% masker
componentNo=1;
precedingSilence=stimulusParameters.stimulusDelay;
stimComponents(maskerEar,componentNo).type=maskerType;
stimComponents(maskerEar,componentNo).toneDuration=maskerDuration;
stimComponents(maskerEar,componentNo).frequencies=maskerFrequency;
stimComponents(maskerEar,componentNo).amplitudesdB=maskerLevel;
stimComponents(maskerEar,componentNo).beginSilence=precedingSilence;
stimComponents(maskerEar,componentNo).endSilence=-1;
stimComponents(maskerEar,componentNo).AMfrequency=0;
stimComponents(maskerEar,componentNo).AMdepth=0;
if rampDuration<maskerDuration
    % ramps must be shorter than the signal
    stimComponents(maskerEar,componentNo).rampOnDur=rampDuration;
    stimComponents(maskerEar,componentNo).rampOffDur=rampDuration;
else
    stimComponents(maskerEar,componentNo).rampOnDur=maskerDuration/2;
    stimComponents(maskerEar,componentNo).rampOffDur=maskerDuration/2;
end
stimComponents(maskerEar,componentNo).phases=...
    stimulusParameters.maskerPhase;
stimComponents(maskerEar,componentNo).niterations=0;    % for IRN only

% target
componentNo=2;
targetDelay=precedingSilence+ maskerDuration+ gapDuration;
stimComponents(targetEar,componentNo).type=targetType;
stimComponents(targetEar,componentNo).OHIOtype=OHIOtype;
stimComponents(targetEar,componentNo).toneDuration=targetDuration;
stimComponents(targetEar,componentNo).frequencies=targetFrequency;
stimComponents(targetEar,componentNo).amplitudesdB=targetLevel;
stimComponents(targetEar,componentNo).beginSilence=targetDelay;
stimComponents(targetEar,componentNo).endSilence=-1;
stimComponents(targetEar,componentNo).AMfrequency=0;
stimComponents(targetEar,componentNo).AMdepth=0;
if rampDuration<targetDuration
    % ramps must be shorter than the signal
    stimComponents(targetEar,componentNo).rampOnDur=rampDuration;
    stimComponents(targetEar,componentNo).rampOffDur=rampDuration;
else
    stimComponents(targetEar,componentNo).rampOnDur=0;
    stimComponents(targetEar,componentNo).rampOffDur=0;
end
stimComponents(targetEar,componentNo).phases=stimulusParameters.targetPhase;
% stimComponents(targetEar,componentNo)

% background same ear as target
componentNo=3;
stimComponents(backgroundEar,componentNo).type=backgroundType;
switch backgroundType
    case 'TEN'
        fileName=['..' filesep '..' filesep ...
            'multithresholdResources' filesep ...
            'backgrounds and maskers'...
            filesep 'ten.wav'];
        [tenNoise, FS]=wavread(fileName);
        
        tenNoise=resample(tenNoise, globalStimParams.FS, FS);
        stimComponents(backgroundEar,componentNo).type='file';
        stimComponents(backgroundEar,componentNo).stimulus=tenNoise';
end
stimComponents(backgroundEar,componentNo).toneDuration=...
    globalStimParams.overallDuration;
stimComponents(backgroundEar,componentNo).amplitudesdB=backgroundLevel;
stimComponents(backgroundEar,componentNo).beginSilence=0;
stimComponents(backgroundEar,componentNo).endSilence=-1;
stimComponents(backgroundEar,componentNo).rampOnDur=rampDuration;
stimComponents(backgroundEar,componentNo).rampOffDur=rampDuration;
stimComponents(backgroundEar,componentNo).AMfrequency=0;
stimComponents(backgroundEar,componentNo).AMdepth=0;

% timings used when evaluating MAP peripheral model
% this is the Slope during which spikes are counted
switch experiment.paradigm
    case 'gapDetection'
        % gap is the 'target' in this case
        stimulusParameters.testTargetBegins=...
            stimulusParameters.stimulusDelay...
            +stimulusParameters.maskerDuration;
        stimulusParameters.testTargetEnds=...
            stimulusParameters.testTargetBegins+withinRuns.variableValue;
        %     case 'SRT'
        %         set(handles.editdigitInput,'visible','off')
    otherwise
        switch experiment.paradigm(1:3)
            case 'OHI'
                stimulusParameters.testTargetBegins=0;
                stimulusParameters.testTargetEnds=OHIOtoneDuration;
            otherwise
                stimulusParameters.testTargetBegins=targetDelay;
                stimulusParameters.testTargetEnds=targetDelay+targetDuration;
        end
end

% ------------------------------------------------------------- play!
% Create and play stimulus (as required by different paradigms)
switch experiment.ear
    case {'statsModelLogistic', 'statsModelRareEvent'}
        audio=[0;0];            % no need to compute stimulus
        
    otherwise                   % create the stimulus
        [targetStimulus, errormsg]= ...
            stimulusCreate(globalStimParams, stimComponents, 0);
        
        if ~isempty(errormsg)   % e.g. limits exceeded
            errormsg
            return
        end
        
        switch experiment.ear
            case {'MAPmodel' , 'MAPmodelMultiCh', 'MAPmodelSingleCh', 'MAPmodelListen'}
                % model requires no calibration correction;
                %  signal is already in Pascals
                globalStimParams.audioOutCorrection=1;
                % use only the targetStimulus for the MAP model
                audio=targetStimulus;
                
            otherwise           % left, right diotic dichotic
                if stimulusParameters.includeCue
                    audio= [cueStimulus;  targetStimulus];
                else            % no cue
                    audio=targetStimulus;
                end
        end
        
        % playtime
        % order of the cue and test stimuli varies for 2AFC
        switch experiment.threshEstMethod
            case {'2I2AFC++', '2I2AFC+++'}
                % intervening silence (currently none; masking delay serves this purpose)
                IAFCinterveningSilence=zeros(round(AFCsilenceDuration/dt),2);
                if rand>0.5				% put test stimulus first
                    stimulusParameters.testTargetBegins=targetDelay ;
                    stimulusParameters.testTargetEnds= ...
                        targetDelay+targetDuration;
                    stimulusParameters.testNonTargetBegins=...
                        length(cueStimulus)*dt ...
                        + AFCsilenceDuration +targetDelay ;
                    stimulusParameters.testNonTargetEnds=...
                        length(cueStimulus)*dt ...
                        + AFCsilenceDuration+targetDelay+targetDuration;
                    
                    set(handles.pushbutton1,'backgroundcolor','r'), drawnow
                    y=audioplayer(targetStimulus, globalStimParams.FS, 24);
                    playblocking(y)
                    set(handles.pushbutton1,'backgroundcolor',...
                        get(0,'defaultUicontrolBackgroundColor')), drawnow
                    y=audioplayer(IAFCinterveningSilence, ...
                        globalStimParams.FS, 24);
                    playblocking(y)
                    set(handles.pushbutton2,'backgroundcolor','r'), drawnow
                    y=audioplayer(cueStimulus, globalStimParams.FS, 24);
                    playblocking(y)
                    set(handles.pushbutton2,'backgroundcolor',...
                        get(0,'defaultUicontrolBackgroundColor')), drawnow
                    withinRuns.stimulusOrder='targetFirst';
                    audio= [targetStimulus; IAFCinterveningSilence; ...
                        cueStimulus];   % for plotting purposes later
                    
                else					% put test stimulus second
                    stimulusParameters.testTargetBegins=...
                        length(cueStimulus)*dt ...
                        + AFCsilenceDuration +targetDelay ;
                    stimulusParameters.testTargetEnds=...
                        length(cueStimulus)*dt ...
                        + AFCsilenceDuration+targetDelay+targetDuration;
                    stimulusParameters.testNonTargetBegins=targetDelay ;
                    stimulusParameters.testNonTargetEnds=...
                        targetDelay+targetDuration;
                    
                    set(handles.pushbutton1,'backgroundcolor','r'),drawnow
                    y=audioplayer(cueStimulus, globalStimParams.FS, 24);
                    playblocking(y)
                    set(handles.pushbutton1,'backgroundcolor',...
                        get(0,'defaultUicontrolBackgroundColor')), drawnow
                    y=audioplayer(IAFCinterveningSilence, ...
                        globalStimParams.FS, 24);
                    playblocking(y)
                    set(handles.pushbutton2,'backgroundcolor','r'), drawnow
                    y=audioplayer(targetStimulus, globalStimParams.FS, 24);
                    playblocking(y)
                    set(handles.pushbutton2,'backgroundcolor',...
                        get(0,'defaultUicontrolBackgroundColor')), drawnow
                    withinRuns.stimulusOrder='targetSecond';
                    audio= [cueStimulus; IAFCinterveningSilence; ...
                        targetStimulus];    % for plotting purposes later
                end
            otherwise                       % singleInterval
                if strcmp(experiment.ear,'MAPmodel') ...
                        || strcmp(experiment.ear,'MAPmodelMultiCh') ...
                        || strcmp(experiment.ear,'MAPmodelSingleCh') ...
                        ||strcmp(experiment.ear,'MAPmodelListen')
                    % don't play for MAPmodel
                    switch experiment.ear
                        % except on special request
                        case {'MAPmodelListen'}
                            y=audioplayer(audio, globalStimParams.FS, 24);
                            playblocking(y) % suspends operations until completed
                    end
                else
                    y=audioplayer(audio, globalStimParams.FS, 24);
                    playblocking(y)
                end	  %   if experiment.ear
        end	% switch experiment.threshEstMethod
end % switch experiment.ear


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

% Panel 1
% graphical presentation of the stimulus
% NB shown *after* the stimulus has been presented
axes(expGUIhandles.axes1), cla
% plot is HW rectified and plotted as dB re 28e-6
% calibration is ignored
t=dt:dt:dt*length(audio);
plot(t,stimulusParameters.calibrationdB+20*log10((abs(audio)+1e-10)/28e-6))
% set(gca,'xtick',[])
ylim([-20 100])
ylabel('stimulus (dB SPL)')
xlim([0 t(end)])
grid on
header=[betweenRuns.variableName1  ': ' ...
    num2str(betweenRuns.var1Sequence(betweenRuns.runNumber))];
header=[header '      ' num2str(...
    betweenRuns.var2Sequence(betweenRuns.runNumber)) ':' ...
    betweenRuns.variableName2 ];
title(header)