diff Copy_of_multithreshold 1.46/subjGUI_MT.m @ 28:02aa9826efe0

mainly multiThreshold
author Ray Meddis <rmeddis@essex.ac.uk>
date Fri, 01 Jul 2011 12:59:47 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Copy_of_multithreshold 1.46/subjGUI_MT.m	Fri Jul 01 12:59:47 2011 +0100
@@ -0,0 +1,1867 @@
+function varargout = subjGUI_MT(varargin)
+
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+    'gui_Singleton',  gui_Singleton, ...
+    'gui_OpeningFcn', @subjGUI_MT_OpeningFcn, ...
+    'gui_OutputFcn',  @subjGUI_MT_OutputFcn, ...
+    'gui_LayoutFcn',  [] , ...
+    'gui_Callback',   []);
+if nargin && isstr(varargin{1})
+    gui_State.gui_Callback = str2func(varargin{1});
+end
+
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+% --- Executes just before subjGUI_MT is made visible.
+function subjGUI_MT_OpeningFcn(hObject, eventdata, handles, varargin)
+
+% Choose default command line output for subjGUI_MT
+handles.output = hObject;
+initializeGUI(handles)
+guidata(hObject, handles);
+
+function varargout = subjGUI_MT_OutputFcn(hObject, eventdata, handles)
+% Get default command line output from handles structure
+varargout{1} = handles.output;
+
+% -----------------------------------------------------initializeGUI
+function initializeGUI(handles)
+global experiment
+global subjectGUIHandles expGUIhandles
+        addpath (['..' filesep 'MAP'], ['..' filesep 'utilities'], ...
+    ['..' filesep 'parameterStore'],  ['..' filesep 'wavFileStore'],...
+    ['..' filesep 'testPrograms'])
+
+dbstop if error
+
+% subjectGUI size and location         % [left bottom width height]
+scrnsize=get(0,'screensize');
+set(0, 'units','pixels')
+switch experiment.ear
+    % use default size unless...
+    case {'MAPmodel',  'MAPmodelMultich', 'MAPmodelSingleCh', ...
+            'statsModelLogistic','statsModelRareEvent'}
+        % 	subjectGUI not needed for modelling so minimize subject GUI
+        set(gcf, 'units','pixels')
+        y=[0*scrnsize(3) 0.8*scrnsize(4) 0.1*scrnsize(3) 0.2*scrnsize(4)];
+        set(gcf,'position',y, 'color',[.871 .961 .996])
+        
+
+        
+    case 'MAPmodelListen',
+        % 	subjectGUI is needed for display purposes. Make it large
+        set(gcf, 'units','pixels')
+        y=[.665*scrnsize(3) 0.02*scrnsize(4) ...
+            0.33*scrnsize(3) 0.5*scrnsize(4)]; % alongside
+        set(gcf,'position',y, 'color',[.871 .961 .996])
+end
+
+switch experiment.ear
+    case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
+        % Look to see if the button box exists and, if so, initialise it
+        buttonBoxIntitialize		% harmless if no button box attached
+end
+
+% function varargout = subjGUI_MT(varargin)
+% 
+% % Begin initialization code - DO NOT EDIT
+% gui_Singleton = 1;
+% gui_State = struct('gui_Name',       mfilename, ...
+%     'gui_Singleton',  gui_Singleton, ...
+%     'gui_OpeningFcn', @subjGUI_MT_OpeningFcn, ...
+%     'gui_OutputFcn',  @subjGUI_MT_OutputFcn, ...
+%     'gui_LayoutFcn',  [] , ...
+%     'gui_Callback',   []);
+% if nargin && isstr(varargin{1})
+%     gui_State.gui_Callback = str2func(varargin{1});
+% end
+% 
+% if nargout
+%     [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+% else
+%     gui_mainfcn(gui_State, varargin{:});
+% end
+% % End initialization code - DO NOT EDIT
+% 
+% % --- Executes just before subjGUI_MT is made visible.
+% function subjGUI_MT_OpeningFcn(hObject, eventdata, handles, varargin)
+% 
+% % Choose default command line output for subjGUI_MT
+% handles.output = hObject;
+% initializeGUI(handles)
+% guidata(hObject, handles);
+% 
+% function varargout = subjGUI_MT_OutputFcn(hObject, eventdata, handles)
+% % Get default command line output from handles structure
+% varargout{1} = handles.output;
+% 
+% % -----------------------------------------------------initializeGUI
+% function initializeGUI(handles)
+% global experiment
+% global subjectGUIHandles expGUIhandles
+% 
+% dbstop if error
+% 
+% % subjectGUI size and location         % [left bottom width height]
+% scrnsize=get(0,'screensize');
+% set(0, 'units','pixels')
+% switch experiment.ear
+%     % use default size unless...
+%     case {'MAPmodel',  'MAPmodelMultiCh','MAPmodelSingleCh',  ...
+%             'statsModelLogistic','statsModelRareEvent'}
+%         % 	subjectGUI not needed for modelling so minimize subject GUI
+%         set(gcf, 'units','pixels')
+%         y=[0*scrnsize(3) 0.8*scrnsize(4) 0.1*scrnsize(3) 0.2*scrnsize(4)];
+%         set(gcf,'position',y, 'color',[.871 .961 .996])
+%         
+%     case 'MAPmodelListen',
+%         % 	subjectGUI is needed for display purposes. Make it large
+%         set(gcf, 'units','pixels')
+%         y=[.665*scrnsize(3) 0.02*scrnsize(4) ...
+%             0.33*scrnsize(3) 0.5*scrnsize(4)]; % alongside
+%         set(gcf,'position',y, 'color',[.871 .961 .996])
+% end
+% 
+% switch experiment.ear
+%     case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
+%         % Look to see if the button box exists and, if so, initialise it
+%         buttonBoxIntitialize		% harmless if no button box attached
+% end
+
+% clear display of previous mean values. This is a new measurement series
+axes(expGUIhandles.axes4), cla           
+reset (expGUIhandles.axes4)
+
+% handles needed in non-callback routines below
+subjectGUIHandles=handles;
+
+% start immediately
+startNewExperiment(handles, expGUIhandles)
+% This is the end of the experiment. Exit here and return to ExpGUI.
+
+% ----------------------------------------------------- startNewExperiment
+function startNewExperiment(handles, expGUIhandles)
+% An experiment consists of a series of 'runs'.
+% Resets all relevant variables at the beginning of a new experiment.
+global experiment stimulusParameters betweenRuns
+
+% 'start new experiment' button is the only valid action now
+experiment.status='waitingForStart';
+
+switch experiment.threshEstMethod
+    % add appropriate labels to subject GUI buttons
+    case {'2I2AFC++', '2I2AFC+++'}
+        set(handles.pushbutton3,'string','')
+        set(handles.pushbutton2,'string','2')
+        set(handles.pushbutton1,'string','1')
+        set(handles.pushbutton0,'string','0')
+    case {'MaxLikelihood', 'oneIntervalUpDown'}
+        if stimulusParameters.includeCue
+            set(handles.pushbutton3,'string','')
+            set(handles.pushbutton2,'string','2')
+            set(handles.pushbutton1,'string','1')
+            set(handles.pushbutton0,'string','0')
+        else
+            set(handles.pushbutton3,'string','')
+            set(handles.pushbutton2,'string','YES')
+            set(handles.pushbutton1,'string','NO')
+            set(handles.pushbutton0,'string','')
+        end
+end
+
+switch experiment.paradigm
+    case 'discomfort'
+        set(handles.pushbutton3,'string','')
+        set(handles.pushbutton2,'string','uncomfortable')
+        set(handles.pushbutton1,'string','loud')
+        set(handles.pushbutton0,'string','comfortable')
+            experiment.allowCatchTrials=0;
+end
+
+% experiment.subjGUIfontSize is set on expGUI
+set(handles.pushbutton3,'FontSize',experiment.subjGUIfontSize)
+set(handles.pushbutton2,'FontSize',experiment.subjGUIfontSize)
+set(handles.pushbutton1,'FontSize',experiment.subjGUIfontSize)
+set(handles.pushbutton0,'FontSize',experiment.subjGUIfontSize)
+set(handles.pushbuttoNotSure,'FontSize',experiment.subjGUIfontSize)
+set(handles.pushbuttonGO,'FontSize',experiment.subjGUIfontSize)
+set(handles.textMSG,'FontSize',experiment.subjGUIfontSize)
+
+set(handles.pushbutton19,'visible','off') % unused button
+
+% start command window summary of progress
+fprintf(' \n ----------- NEW MEASUREMENTS\n')
+disp(['paradigm:   ' experiment.paradigm])
+cla(expGUIhandles.axes1)
+cla(expGUIhandles.axes2)
+cla(expGUIhandles.axes4)
+cla(expGUIhandles.axes5)
+
+experiment.stop=0;              % status of 'stop' button
+experiment.pleaseRepeat=0;      % status of 'repeat' button
+experiment.buttonBoxStatus='not busy';
+
+% date and time and replace ':' with '_'
+date=datestr(now);idx=findstr(':',date);date(idx)='_'; 
+experiment.date=date;
+timeNow=clock; betweenRuns.timeNow= timeNow;
+experiment.timeAtStart=[num2str(timeNow(4)) ':' num2str(timeNow(5))];
+experiment.minElapsed=0; 
+
+% unpack catch trial rates. The rate declines from the start rate 
+%  to the base rate using a time constant.
+stimulusParameters.catchTrialRate=stimulusParameters.catchTrialRates(1);
+stimulusParameters.catchTrialBaseRate=...
+    stimulusParameters.catchTrialRates(2);
+stimulusParameters.catchTrialTimeConstant=...
+    stimulusParameters.catchTrialRates(3);
+if stimulusParameters.catchTrialBaseRate==0
+    stimulusParameters.catchTrialRate=0;
+end
+
+% for human measurements only, identify the start catch trial rate
+switch experiment.ear
+    case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
+        fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
+            stimulusParameters.catchTrialRate)
+end
+
+% Reset betweenRuns parameters. this occurs only at experiment start
+% withinRuns values are reset in 'startNewRun'
+% this approach creates a more readable structure summary printout.
+betweenRuns.thresholds=[];
+betweenRuns.thresholds_mean=[];
+betweenRuns.thresholds_median=[];
+betweenRuns.forceThresholds=[];
+betweenRuns.observationCount=[];
+betweenRuns.catchTrials=[];
+betweenRuns.timesOfFirstReversals=[];
+betweenRuns.bestThresholdTracks=[];
+betweenRuns.levelTracks=[];
+betweenRuns.responseTracks=[];
+betweenRuns.slopeKTracks=[];
+betweenRuns.gainTracks=[];
+betweenRuns.VminTracks=[];
+betweenRuns.bestGain=[];
+betweenRuns.bestVMin=[];
+betweenRuns.bestPaMin=[];
+betweenRuns.bestLogisticM=[];
+betweenRuns.bestLogisticK=[];
+betweenRuns.resets=0;
+betweenRuns.runNumber=0;
+
+% Up to two parameters can be changed between runs
+% Find the variable parameters and randomize them
+% e.g. 'variableList1 = stimulusParameters.targetFrequency;'
+eval(['variableList1=stimulusParameters.' betweenRuns.variableName1 ';']);
+eval(['variableList2=stimulusParameters.' betweenRuns.variableName2 ';']);
+nVar1=length(variableList1);
+nVar2=length(variableList2);
+
+% Create two sequence vectors to represent the sequence of var1 and var2 
+% values. 'var1' changes most rapidly.
+switch betweenRuns.randomizeSequence
+    case 'fixed sequence'
+        var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2);
+        var2Sequence=reshape(repmat(betweenRuns.variableList2, ...
+            nVar1,1),1,nVar1*nVar2);
+    case 'randomize within blocks'
+        % the blocks are not randomized
+        var1Sequence=betweenRuns.variableList1;
+        ranNums=rand(1, length(var1Sequence)); [x idx]=sort(ranNums);
+        var1Sequence=var1Sequence(idx);
+        betweenRuns.variableList1=variableList1(idx);
+        var1Sequence=repmat(var1Sequence, 1,nVar2);
+        var2Sequence=reshape(repmat(betweenRuns.variableList2, nVar1,1)...
+            ,1,nVar1*nVar2);
+    case 'randomize across blocks'
+        var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2);
+        var2Sequence=reshape(repmat(betweenRuns.variableList2, nVar1,1),...
+            1,nVar1*nVar2);
+        ranNums=rand(1, nVar1*nVar2);
+        [x idx]=sort(ranNums);
+        var1Sequence=var1Sequence(idx);
+        var2Sequence=var2Sequence(idx);
+        % there should be one start value for every combination 
+        %  of var1/ var2. In principle this allows these values to be 
+        % programmed. Not currently in use.
+        stimulusParameters.WRVstartValues=...
+            stimulusParameters.WRVstartValues(idx);
+end
+betweenRuns.var1Sequence=var1Sequence;
+betweenRuns.var2Sequence=var2Sequence;
+
+% caught out vector needs to be linked to the length of the whole sequence
+betweenRuns.caughtOut=zeros(1,length(var1Sequence));
+
+disp('planned sequence:')
+if min(var1Sequence)>1
+    % use decidaml places only if necessary
+disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%6.0f')  ])
+else
+disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%8.3f')  ])
+end
+if min(var1Sequence)>1
+disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%6.0f') ])
+else
+disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%8.3f') ])
+end
+
+fprintf('\nvariable1 \t  variable2\t  \n')
+fprintf('%s \t  %s\t  Threshold  \n',betweenRuns.variableName1,...
+    betweenRuns.variableName2)
+
+% Light up 'GO' on subjGUI and advise.
+set(handles.editdigitInput,'visible','off')
+switch experiment.ear
+    case {'statsModelLogistic', 'statsModelRareEvent',...
+            'MAPmodel',  'MAPmodelMultiCh','MAPmodelSingleCh'}
+        % no changes required if model used
+    otherwise
+        set(handles.pushbuttonGO,'backgroundcolor','y')
+        set(handles.pushbuttonGO,'visible','on')
+        set(handles.frame1,'visible','off')
+        set(handles.textMSG,'backgroundcolor', 'w')
+        msg=[{'Ready to start new Experiment'}, {' '}, {'Please, click on the GO button'}];
+        set(handles.textMSG,'string', msg)
+        
+        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) % to allow display to be drawn
+end
+
+% Selecting the 'GO' button is the only valid operation action now
+experiment.status='waitingForGO'; 	% i.e. waiting for new run
+
+% control is now either manual, model (MAP) or randomization
+switch experiment.ear
+    case {'MAPmodel','MAPmodelMultiCh','MAPmodelSingleCh','MAPmodelListen'}                                     % MAP model is now the subject
+        stimulusParameters.calibrationdB=0;             % Pascals required!
+        MAPmodelRunsGUI(handles)
+        % model is now the subject
+    case  {'statsModelLogistic', 'statsModelRareEvent'}	
+        % no catch trials for the statistical model
+        stimulusParameters.catchTrialBaseRate=0;		
+        stimulusParameters.catchTrialRate=0;
+        statsModelRunsGUI(handles)
+    otherwise
+        %manual operation; wait for user to click on 'GO'
+end
+
+% Experiment complete (after MAP or randomization)
+% return to  'initializeGUI' and then back to expGUI
+% Manual control finds its own way home. Program control assumed when
+% the user hits the GO button
+
+% -----------------------------------------------------------------   startNewRun
+function startNewRun(handles)
+% There are many ways to arrive here.
+%  Under manual control this is achieved by hitting the GO button
+%   either via the button box or a mouse click
+%  MAP and randomization methods call this too
+
+global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
+global LevittControl rareEvent
+
+figure(handles.figure1) % guarantee subject GUI visibility
+
+% ignore call if program is not ready
+if ~strcmp(experiment.status,'waitingForGO'), return, end
+
+set(handles.pushbuttonGO,'visible','off')
+
+% append message to expGUI message box to alert experimenter that the user
+% is active
+addToMsg('Starting new trial',0)
+
+cla(expGUIhandles.axes1),  title(''); % stimulus
+cla(expGUIhandles.axes2),  title(''); % WRV track
+drawnow
+
+betweenRuns.runNumber=betweenRuns.runNumber + 1;
+
+withinRuns.trialNumber=1;
+withinRuns.variableValue=...
+    stimulusParameters.WRVstartValues(betweenRuns.runNumber);
+% add random jitter to start level
+if ~experiment.singleShot
+    % SS or single shot allows the user to precisely set the WRV
+    withinRuns.variableValue=withinRuns.variableValue +...
+        (rand-0.5)*stimulusParameters.jitterStartdB;
+end
+
+withinRuns.peaks=[];
+withinRuns.troughs=[];
+withinRuns.levelList=[];
+withinRuns.meanEstTrack=[];
+withinRuns.bestSlopeK=[];
+withinRuns.bestGain=[];
+withinRuns.bestVMin=[];
+withinRuns.forceThreshold=NaN;
+withinRuns.responseList=[];
+withinRuns.caughtOut=0;
+withinRuns.wrongButton=0;
+withinRuns.catchTrialCount=0;
+withinRuns.thresholdEstimateTrack=[];
+
+withinRuns.beginningOfPhase2=0;
+withinRuns.nowInPhase2=0;
+withinRuns.thisIsRepeatTrial=0;
+
+rareEvent.Euclid=NaN;
+rareEvent.bestGain=NaN;
+rareEvent.bestVMin=NaN;
+rareEvent.thresholddB=0;
+rareEvent.bestPaMindB=NaN;
+rareEvent.predictionLevels=[];
+rareEvent.predictionsRE=[];
+
+LevittControl.sequence=[];
+
+% on-screen count of number of runs still to complete
+trialsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber;
+set(handles.toGoCounter,'string', trialsToGo);
+
+switch experiment.threshEstMethod
+    case {'2I2AFC++', '2I2AFC+++'}
+        % For 2I2AFC the buttons need to be on the screen ab initio
+        Levitt2      % inititalize Levitt2 procedure
+end
+
+switch experiment.ear
+    case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
+        % allow subject time to recover from 'go' press
+        pause(experiment.clickToStimulusPause)
+end
+
+errormsg=nextStimulus(handles);				% get the show on the road
+
+% switch experiment.paradigm
+%     case 'SRT'
+%         set(handles.editdigitInput,'visible','on')
+%         uicontrol(handles.editdigitInput)
+% end
+
+% terminate if there is any kind of problem
+if ~isempty(errormsg)
+    % e.g. limits exceeded, clipping
+    disp(errormsg)
+    runCompleted(handles)
+    return
+end
+
+% return route is variable (see intro to this function)
+
+% -----------------------------------------------------buttonBox_callback
+function buttonBox_callback(obj, info)
+global experiment
+global serobj
+global subjectGUIHandles
+
+% do not accept callback if one is already in process
+if strcmp(experiment.buttonBoxStatus,'busy')
+    disp(' ignored button press')
+    return
+end
+experiment.buttonBoxStatus='busy';
+% fclose(serobj)
+
+% identify the code of the button pressed
+buttonPressedNo = fscanf(serobj,'%c',1);
+
+% This is the map from the button to the Cedrus codes
+switch experiment.buttonBoxType
+    case 'horizontal'
+        pbGo='7'; 		pb0='1';		
+        pb1='2';		pb2='3';		
+        pbRepeat='4';	pbWrong='6';	pbBlank='5';
+    case 'square'
+        pbGo='7';		pb0='1';		
+        pb1='3';		pb2='4';		
+        pbRepeat='8';	pbWrong='6';	pbBlank='5';
+end
+
+% decide what to do
+switch experiment.status
+    case {'presentingStimulus', 'waitingForStart', 'trialcompleted', ...
+            'endOfExperiment'}
+        disp(' ignored button press')
+        
+    case 'waitingForGO'
+        % i.e. waiting for new run
+        if strcmp(buttonPressedNo,pbGo)			% only GO button  accepted
+            startNewRun(subjectGUIHandles)
+        else
+            disp(' ignored button press')
+        end
+        
+    case 'waitingForResponse'
+        % response to stimuli
+        switch buttonPressedNo
+            case pb0						% button 0 (top left)
+                switch experiment.threshEstMethod
+                    case {'2I2AFC++', '2I2AFC+++'}
+                        disp(' ignored button press')
+                    otherwise
+                        set(subjectGUIHandles.pushbutton0,...
+                            'backgroundcolor','r')
+                        pause(.1)
+                        set(subjectGUIHandles.pushbutton0,...
+                            'backgroundcolor',get(0,...
+                            'defaultUicontrolBackgroundColor'))
+                        userSelects0or1(subjectGUIHandles)
+                end
+                
+            case pb1						% button 1 (bottom left)
+                switch experiment.threshEstMethod
+                    case {'2I2AFC++', '2I2AFC+++'}
+                        userSelects0or1(subjectGUIHandles)   
+                    otherwise
+                        set(subjectGUIHandles.pushbutton1,...
+                            'backgroundcolor','r')
+                        pause(.1)
+                        set(subjectGUIHandles.pushbutton1,...
+                            'backgroundcolor',get(0,...
+                            'defaultUicontrolBackgroundColor'))
+                        userSelects0or1(subjectGUIHandles)
+                end
+                
+            case pb2						% button 2 (bottom right)
+                switch experiment.threshEstMethod
+                    case {'2I2AFC++', '2I2AFC+++'}
+                        userSelects2 (subjectGUIHandles)
+                    otherwise
+                        set(subjectGUIHandles.pushbutton2,...
+                            'backgroundcolor','r')
+                        pause(.1)
+                        set(subjectGUIHandles.pushbutton2,...
+                            'backgroundcolor',get(0,...
+                            'defaultUicontrolBackgroundColor'))
+                        userSelects2 (subjectGUIHandles)
+                end
+                
+            case pbRepeat                   % extreme right button
+                switch experiment.threshEstMethod
+                    case {'2I2AFC++', '2I2AFC+++'}
+                        disp(' ignored button press')
+                    otherwise
+                        
+                        set(subjectGUIHandles.pushbuttoNotSure,...
+                            'backgroundcolor','r')
+                        pause(.1)
+                        set(subjectGUIHandles.pushbuttoNotSure,...
+                            'backgroundcolor',get(0,...
+                            'defaultUicontrolBackgroundColor'))
+                        userSelectsPleaseRepeat (subjectGUIHandles)
+                end
+                
+            case {pbWrong, pbBlank}
+                disp(' ignored button press')
+                
+            otherwise						% unrecognised button
+                disp('ignored button press')
+        end									% end (button press number)
+    otherwise
+        disp('ignored button press')
+end											% experiment status
+
+% All processing returns through here. 
+% 	fopen(serobj);		% flushes the input buffer
+
+% buttonPressedNo = fscanf(serobj,'%c',1);
+
+% button box remains 'busy' until after the stimulus has been presented
+experiment.buttonBoxStatus='not busy';
+
+% -------------------------------------------------- pushbuttonGO_Callback
+function pushbuttonGO_Callback(hObject, eventdata, handles)
+% This is a mouse click path
+% GO function is also called directly from button box
+%  and from MAP model and stats model
+
+set(handles.pushbuttonGO,'visible','off')
+startNewRun(handles)
+
+% ---------------------------------------------------pushbutton0_Callback
+function pushbutton0_Callback(hObject, eventdata, handles)
+global experiment
+% This is a mouse click path
+
+% ignore 0 button if 2I2AFC used
+if findstr(experiment.threshEstMethod,'2I2AFC'), return, end   	
+
+% userDoesNotHearTarget(handles)		% only possible interpretation
+userDecides(handles, false)
+
+% -------------------------------------------------- pushbutton1_Callback
+function pushbutton1_Callback(hObject, eventdata, handles)
+userSelects0or1(handles)				% also called from buttonBox
+
+% ---------------------------------------------------pushbutton2_Callback
+function pushbutton2_Callback(hObject, eventdata, handles)
+userSelects2(handles)					% also called from buttonBox
+
+% --------------------------------------------- pushbuttoNotSure_Callback
+function pushbuttoNotSure_Callback(hObject, eventdata, handles)
+userSelectsPleaseRepeat(handles)		% also called from buttonBox
+
+% -------------------------------------------------- pushbutton3_Callback
+function pushbutton3_Callback(hObject, eventdata, handles)
+
+% ------------------------------------------------- pushbutton19_Callback
+function pushbutton19_Callback(hObject, eventdata, handles)
+% should be invisible (ignore)
+
+% --------------------------------------- pushbuttonWrongButton_Callback
+function pushbuttonWrongButton_Callback(hObject, eventdata, handles)
+userSelectsWrongButton(handles)
+
+% --------------------------------------- editdigitInput_Callback
+function editdigitInput_Callback(hObject, eventdata, handles)
+userSelects0or1(handles)				% after digit string input
+
+
+
+% ----------------------------------------------------- userSelects0or1
+function userSelects0or1(handles)
+global experiment withinRuns
+
+switch experiment.threshEstMethod			
+    case {'2I2AFC++', '2I2AFC+++'}
+        switch withinRuns.stimulusOrder
+            case 'targetFirst';
+                %                 userHearsTarget(handles)
+                userDecides(handles, true)
+            otherwise
+                %                 userDoesNotHearTarget(handles)
+                userDecides(handles, false)
+        end
+    otherwise
+        % single interval
+        % 0 or 1 are treated as equivalent (i.e. target is not heard)
+        userDecides(handles, false)
+end
+% return to pushButton1 callback
+
+% ----------------------------------------------------- userSelects2
+function userSelects2(handles)
+global experiment withinRuns
+switch experiment.threshEstMethod			
+    case {'2I2AFC++', '2I2AFC+++'}
+        switch withinRuns.stimulusOrder
+            case 'targetSecond';
+                %                 userDoesNotHearTarget(handles)
+                userDecides(handles, true)
+            otherwise
+                %                 userHearsTarget(handles)
+                userDecides(handles, false)
+        end
+    otherwise
+        % single interval (2 targets heard)
+        userDecides(handles, true)
+end
+% return to pushButton2 callback
+
+% ----------------------------------------------------- ---- userDecides
+function userDecides(handles, saidYes)
+global experiment stimulusParameters betweenRuns withinRuns
+global rareEvent logistic psy levelsBinVector
+
+if experiment.singleShot
+    return
+end
+
+% ignore click if not 'waitingForResponse'
+if ~strcmp(experiment.status,'waitingForResponse')
+    disp('ignored click')
+    return
+end
+
+% speech reception threshold
+if strcmp(stimulusParameters.targetType,'digitStrings')
+    digitsInput=get(handles.editdigitInput,'string');
+    % must be three digits
+    if ~(length(digitsInput)==3)
+        addToMsg(['error message: Wrong no of digits'], 0, 1)
+        set(handles.textMSG,'string', 'Wrong no of digits', ...
+            'BackgroundColor','r', 'ForegroundColor', 'w')
+        set(handles.editdigitInput,'string','')
+
+        return
+    end
+    % obtain correct answer from file name
+    x=stimulusParameters.digitString;
+    idx=find(x=='O'); x(idx)='0'; % replace 'oh' with zero
+
+    disp([x '   ' digitsInput])
+
+    if x==digitsInput
+        saidYes=1;
+    else
+        saidYes=0;
+    end
+set(handles.editdigitInput,'string','')
+set(handles.editdigitInput,'visible','off')
+pause(0.1)
+end
+
+
+
+% no button presses accepted while processing
+experiment.status='processingResponse';
+
+% catch trials. Restart trial if caught
+if withinRuns.catchTrial
+    if saidYes
+        disp('catch trial - caught out')
+        withinRuns.caughtOut=withinRuns.caughtOut+1;
+        
+        % special: estimate caught out rate by allowing the trial 
+        %  to continue after catch
+        if stimulusParameters.catchTrialBaseRate==0.5
+            %  To use this facility, set the catchTrialRate and the 
+            %   catchTrialBaseRate both to 0.5
+            %    update false positive rate
+            betweenRuns.caughtOut(betweenRuns.runNumber)=...
+                withinRuns.caughtOut;         
+            plotProgressThisTrial(handles)
+            nextStimulus(handles);
+            return
+        end
+        
+        % Punishment: restart the trial
+        set(handles.frame1,'backgroundColor','r')
+        set(handles.pushbuttonGO, ...
+            'visible','on', 'backgroundcolor','y') % and go again
+        msg=[{'Start again: catch trial error'}, {' '},...
+            {'Please,click on the GO button'}];
+        set(handles.textMSG,'string',msg)
+        [y,fs]=wavread('ding.wav');
+        wavplay(y/100,fs)
+        
+        % raise catch trial rate temporarily. 
+        %  this is normally reduced on each new trial (see GO)
+        stimulusParameters.catchTrialRate=...
+            stimulusParameters.catchTrialRate+0.1;
+        if stimulusParameters.catchTrialRate>0.5 
+            stimulusParameters.catchTrialRate=0.5; 
+        end
+        fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
+            stimulusParameters.catchTrialRate)
+        
+        betweenRuns.caughtOut(betweenRuns.runNumber)=...
+            1+betweenRuns.caughtOut(betweenRuns.runNumber);
+        betweenRuns.runNumber=betweenRuns.runNumber-1;
+        experiment.status='waitingForGO';
+        return % unwind and wait for button press
+    else % (said No)
+        % user claims not to have heard target. fortunate as it was not
+        %  present. So, repeat the stimulus (possibly with target)
+        %  and behave as if the last trial did not occur
+        errormsg=nextStimulus(handles);
+        
+        % terminate if there is any kind of problem
+        if ~isempty(errormsg)
+            % e.g. limits exceeded, clipping
+            disp(['Error nextStimulus: ' errormsg])
+            runCompleted(handles)
+            return
+        end
+        return      % no further action - next trial
+    end
+end
+
+% This section analyses the responses, makes tracks and defines next stim.
+
+% Define response and update response list
+if saidYes
+    % target was heard, so response=1;
+    withinRuns.responseList=[withinRuns.responseList 1];	% 'heard it!'
+else
+    % target was not hear heard, so response=0;
+    withinRuns.responseList=[withinRuns.responseList 0];
+end
+withinRuns.levelList=[withinRuns.levelList withinRuns.variableValue];
+trialNumber=length(withinRuns.responseList);
+
+% keep track of peaks and troughs;
+% identify direction of change during initial period
+if saidYes
+    % default step size before first reversal
+    WRVinitialStep=-stimulusParameters.WRVinitialStep; 
+    WRVsmallStep=-stimulusParameters.WRVsmallStep;
+    % if the previous direction was 'less difficult', this must be a peak
+    if strcmp(withinRuns.direction,'less difficult') ...
+            && length(withinRuns.levelList)>1
+        withinRuns.peaks=[withinRuns.peaks withinRuns.variableValue];
+    end
+    withinRuns.direction='more difficult';
+    
+else
+    % said 'no'
+    % default step size before first reversal
+    WRVinitialStep=stimulusParameters.WRVinitialStep; 
+    WRVsmallStep=stimulusParameters.WRVsmallStep;
+    
+    % if the previous direction was 'up', this must be a peak
+    if strcmp(withinRuns.direction,'more difficult') ...
+            && length(withinRuns.levelList)>1
+        withinRuns.troughs=[withinRuns.troughs withinRuns.variableValue];
+    end
+    withinRuns.direction='less difficult';
+end
+
+% phase 2 is all the levels after and incuding the first reversal 
+%  plus the level before that
+if ~withinRuns.nowInPhase2 && length(withinRuns.peaks)+ ...
+        length(withinRuns.troughs)>0
+% if ~withinRuns.nowInPhase2 && (~isempty(withinRuns.peaks) ...
+%         || ~isempty(withinRuns.troughs))
+    % define phase 2
+    withinRuns.beginningOfPhase2=trialNumber-1;
+    withinRuns.nowInPhase2=1;
+    WRVsmallStep=WRVinitialStep/2;
+end
+
+if withinRuns.nowInPhase2
+    % keep a record of all levels and responses in phase 2 only
+    withinRuns.levelsPhaseTwo=...
+        withinRuns.levelList(withinRuns.beginningOfPhase2:end);
+    withinRuns.responsesPhaseTwo=...
+        withinRuns.responseList(withinRuns.beginningOfPhase2:end);
+else
+    withinRuns.levelsPhaseTwo=[];
+end
+
+
+% get (or substitute) threshold estimate
+switch experiment.threshEstMethod
+    case {'2I2AFC++', '2I2AFC+++'}
+        % for plotting psychometric function only
+        if withinRuns.beginningOfPhase2>0
+            [psy, levelsBinVector, logistic, rareEvent]= ...
+                bestFitPsychometicFunctions...
+                (withinRuns.levelsPhaseTwo,  withinRuns.responsesPhaseTwo);
+        end
+        
+        if ~isempty(withinRuns.peaks) && ~isempty(withinRuns.troughs)
+            thresholdEstimate= ...
+                mean([mean(withinRuns.peaks) mean(withinRuns.troughs)]);
+        else
+            thresholdEstimate=NaN;
+        end
+    otherwise
+        % single interval methods
+        try
+            % using the s trial after the first reversal
+            [psy, levelsBinVector, logistic, rareEvent]= ...
+                bestFitPsychometicFunctions(withinRuns.levelsPhaseTwo,...
+                withinRuns.responsesPhaseTwo);
+        catch
+            logistic.bestThreshold=NaN;
+        end
+end
+
+if withinRuns.nowInPhase2
+    % save tracks of threshold estimates for plotting andprinting
+    switch experiment.functionEstMethod
+        case {'logisticLS', 'logisticML'}
+            if withinRuns.nowInPhase2
+                withinRuns.meanEstTrack=...
+                    [withinRuns.meanEstTrack ...
+                    mean(withinRuns.levelsPhaseTwo)];
+                withinRuns.thresholdEstimateTrack=...
+                    [withinRuns.thresholdEstimateTrack ...
+                    logistic.bestThreshold];
+            end
+        case 'rareEvent'
+            withinRuns.meanEstTrack=...
+                [withinRuns.meanEstTrack rareEvent.thresholddB];
+            withinRuns.thresholdEstimateTrack=...
+                [withinRuns.thresholdEstimateTrack logistic.bestThreshold];
+        case 'peaksAndTroughs'
+            withinRuns.meanEstTrack=...
+                [withinRuns.meanEstTrack thresholdEstimate];
+            withinRuns.thresholdEstimateTrack=...
+                [withinRuns.thresholdEstimateTrack thresholdEstimate];
+    end
+end
+
+% special discomfort condition
+% run is completed when subject hits '2' button
+switch experiment.paradigm
+    case 'discomfort'
+        if saidYes
+            runCompleted(handles)
+            return
+        end
+end
+
+% choose the next level for the stimulus
+switch experiment.threshEstMethod
+    case {'2I2AFC++', '2I2AFC+++'}
+        if saidYes
+            [WRVinitialStep, msg]=Levitt2('hit', withinRuns.variableValue);
+        else
+            [WRVinitialStep, msg]=Levitt2('miss',withinRuns.variableValue);
+        end
+        
+        % empty message means continue as normal
+        if ~isempty(msg)				
+            runCompleted(handles)
+            return
+        end
+        newWRVvalue=withinRuns.variableValue-WRVinitialStep;
+        
+    case {'MaxLikelihood', 'oneIntervalUpDown'}
+        % run completed by virtue of number of trials               
+        % or restart because listener is in trouble
+        if length(withinRuns.levelsPhaseTwo)== experiment.maxTrials
+            % Use bonomial test to decide if there is an imbalance in the
+            % number of 'yes'es and 'no's
+            yesCount=sum(withinRuns.responseList);
+            noCount=length(withinRuns.responseList)-yesCount;
+            z=abs(yesCount-noCount)/(yesCount+noCount)^0.5;
+            if z>1.96
+                betweenRuns.resets=betweenRuns.resets+1;
+                disp([ 'reset / z= ' num2str( z)  ...
+                    '   Nresets= ' num2str( betweenRuns.resets) ] )
+                withinRuns.peaks=[];
+                withinRuns.troughs=[];
+                withinRuns.levelList=withinRuns.levelList(end);
+                withinRuns.meanEstTrack=withinRuns.meanEstTrack(end);
+                withinRuns.forceThreshold=NaN;
+                withinRuns.responseList=withinRuns.responseList(end);
+                withinRuns.beginningOfPhase2=0;
+                withinRuns.nowInPhase2=0;
+                withinRuns.thresholdEstimateTrack=...
+                    withinRuns.thresholdEstimateTrack(end);
+            else
+                runCompleted(handles)
+                return
+            end
+        end
+        
+        % set new value for WRV
+        if withinRuns.nowInPhase2
+            % phase 2
+            currentMeanEst=withinRuns.thresholdEstimateTrack(end);
+            switch experiment.threshEstMethod
+                case 'MaxLikelihood'
+                    newWRVvalue=currentMeanEst;                    
+                case {'oneIntervalUpDown'}
+                    newWRVvalue=withinRuns.variableValue+WRVsmallStep;
+            end
+        else
+            % phase 1
+            if withinRuns.variableValue+2*WRVinitialStep>...
+                    stimulusParameters.WRVlimits(2)
+                % use smaller steps when close to maximum
+                WRVinitialStep=WRVinitialStep/2;
+            end
+            newWRVvalue=withinRuns.variableValue+WRVinitialStep;
+        end
+    otherwise
+        error(  'assessment method not recognised')
+end
+
+switch experiment.paradigm
+    % prevent unrealistic gap durations 'gapDetection' tasks.
+    % Note that the gap begins when the ramp ends not when stimulus ends
+    case 'gapDetection'
+        if newWRVvalue<-2*stimulusParameters.rampDuration
+            newWRVvalue=-2*stimulusParameters.rampDuration;
+            addToMsg('gap duration fixed at - 2 * ramp!',1, 1)
+        end
+end
+
+withinRuns.variableValue=newWRVvalue;
+withinRuns.trialNumber=withinRuns.trialNumber+1;
+
+% Trial continues
+plotProgressThisTrial(handles)
+
+% next stimulus and so the cycle continues
+errormsg=nextStimulus(handles);
+% after the stimulus is presented, control returns here and the system
+% waits for user action.
+
+% terminate if there is any kind of problem
+if ~isempty(errormsg)
+    % e.g. limits exceeded, clipping
+    disp(['Error nextStimulus: ' errormsg])
+    runCompleted(handles)
+    return
+end
+
+% ------------------------------------------------ userSelectsPleaseRepeat
+function userSelectsPleaseRepeat(handles)
+global experiment withinRuns
+% ignore click if not 'waitingForResponse'
+if ~strcmp(experiment.status,'waitingForResponse')
+    disp('ignored click')
+    return
+end
+% Take no action other than to make a 
+%  tally of repeat requests
+experiment.pleaseRepeat=experiment.pleaseRepeat+1;
+withinRuns.thisIsRepeatTrial=1;
+nextStimulus(handles);
+
+% ------------------------------------------------ userSelectsWrongButton
+function userSelectsWrongButton(handles)
+global withinRuns experiment
+% restart is the simplest solution for a 'wrong button' request
+withinRuns.wrongButton=withinRuns.wrongButton+1;
+set(handles.pushbuttonGO, 'visible','on', 'backgroundcolor','y') 
+msg=[{'Start again: wrong button pressed'}, {' '},...
+    {'Please,click on the GO button'}];
+set(handles.textMSG,'string',msg)
+experiment.status='waitingForGO';
+
+% ------------------------------------------------- plotProgressThisTrial
+function plotProgressThisTrial(handles)
+
+% used for all responses
+global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
+global  psy levelsBinVector binFrequencies rareEvent logistic statsModel
+
+
+% plot the levelTrack and the threshold track
+
+% Panel 2
+% plot the levelList
+axes(expGUIhandles.axes2); cla
+plot( withinRuns.levelList,'o','markerFaceColor','k'), hold on
+% plot the best threshold estimate tracks
+if length(withinRuns.meanEstTrack)>=1
+    % The length of the levelList is 2 greater than number of thresholds
+    ptr=withinRuns.beginningOfPhase2+1;
+    plot(ptr: ptr+length(withinRuns.meanEstTrack)-1, ...
+        withinRuns.meanEstTrack, 'r')
+    plot( ptr: ptr+length(withinRuns.thresholdEstimateTrack)-1, ...
+        withinRuns.thresholdEstimateTrack, 'g')
+    hold off
+    estThresh=withinRuns.thresholdEstimateTrack(end);
+    switch experiment.threshEstMethod
+        % add appropriate labels to subject GUI buttons
+        case {'2I2AFC++', '2I2AFC+++'}
+            title([stimulusParameters.WRVname ' = ' ...
+                num2str(withinRuns.variableValue, '%5.1f')])
+        otherwise
+            title([stimulusParameters.WRVname ' = ' ...
+                num2str(withinRuns.variableValue, '%5.1f') ...
+                ';    TH= ' num2str(estThresh, '%5.1f')])
+    end
+end
+xlim([0 experiment.maxTrials+withinRuns.beginningOfPhase2]);
+ylim(stimulusParameters.WRVlimits)
+grid on
+
+% Panel 4: Summary of threshold estimates (not used here)
+% Earlier estimates are set in 'runCompleted'
+% However, title shows runs/trials remaining
+
+axes(expGUIhandles.axes4)
+runsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber;
+if withinRuns.beginningOfPhase2>0
+    trialsToGo= experiment.singleIntervalMaxTrials(1) ...
+        + withinRuns.beginningOfPhase2- withinRuns.trialNumber;
+    title(['trials remaining = ' num2str(trialsToGo) ...
+        ':    runs to go= ' num2str(runsToGo)])
+end
+
+% plot psychometric function   - panel 5
+axes(expGUIhandles.axes5), cla
+plot(withinRuns.levelList, withinRuns.responseList,'b.'), hold on
+ylim([0 1])
+title('')
+
+switch experiment.threshEstMethod
+    case {'MaxLikelihood', 'oneIntervalUpDown'}
+        if withinRuns.beginningOfPhase2>0
+            % display only when in phase 2.
+            withinRuns.levelsPhaseTwo=...
+                withinRuns.levelList(withinRuns.beginningOfPhase2:end);
+            withinRuns.responsesPhaseTwo=...
+                withinRuns.responseList(withinRuns.beginningOfPhase2:end);
+            
+            % organise data as psychometric function
+            [psy, levelsBinVector, binFrequencies]= ...
+                psychometricFunction(withinRuns.levelsPhaseTwo,...
+                withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
+            
+            % Plot the function
+            %   point by point with circles of appropiate weighted size
+            hold on,
+            for i=1:length(psy)
+                plot(levelsBinVector(i), psy(i), 'ro', ...
+                    'markersize', 50*binFrequencies(i)/sum(binFrequencies))
+            end
+            % save info for later
+            betweenRuns.psychometicFunction{betweenRuns.runNumber}=...
+                [levelsBinVector; psy];
+            
+            % fitPsychometric functions is  computed in 'userDecides'
+            % plot(rareEvent.predictionLevels, rareEvent.predictionsRE,'k')
+            plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
+            plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
+            if ~isnan(logistic.bestThreshold )
+%                 xlim([ (logistic.bestThreshold -20) ...
+%                     (logistic.bestThreshold +20) ])
+                xlim([ 0 100 ])
+%                 if logistic.bestK< max(experiment.possLogSlopes)
+                    title(['k= ' num2str(logistic.bestK, '%6.2f') ' g= '...
+                        num2str(rareEvent.bestGain,'%6.3f') '  A=' ...
+                        num2str(rareEvent.bestVMin,'%8.1f')])
+%                     title('')
+%                 end
+            else
+                title(' ')
+            end
+            
+            switch experiment.ear
+                %plot green line for statsModel a priori model
+                case 'statsModelLogistic'
+                    % plot proTem logistic (green) used by stats model
+                    p= 1./(1+exp(-statsModel.logisticSlope...
+                        *(levelsBinVector-logistic.bestThreshold)));
+                    if experiment.psyFunSlope<0, p=1-p;end
+                    titleText=[ ',  statsModel: logistic'];
+                    hold on,    plot(levelsBinVector, p,'g')
+                case  'statsModelRareEvent'
+                    pressure=28*10.^(levelsBinVector/20);
+                    p=1-exp(-stimulusParameters.targetDuration...
+                        *(statsModel.rareEvenGain...
+                        * pressure-statsModel.rareEventVmin));
+                    p(p<0)=0;
+                    if experiment.psyFunSlope<0, p=1-p;end
+                    hold on,    plot(levelsBinVector, p,'g')
+            end %(estMethod)
+        end
+    otherwise           % 2A2IFC
+        
+        message3= ...
+            ([ 'peaks='  num2str(withinRuns.peaks) ...
+            'troughs='  num2str(withinRuns.troughs)]);
+        ylimRM([-0.1 1.1])	% 0=no / 1=yes
+        set(gca,'ytick',[0 1], 'yTickLabel', {'no';'yes'})
+        ylabel('psychometric function'), xlabel('target level')
+        if length(levelsBinVector)>1
+            xlim([ min(levelsBinVector) max(levelsBinVector)])
+            xlim([ 0 100])
+        end
+end
+
+% command window summary
+% Accumulate things to say in the message window
+message1= (['responses:      ' num2str(withinRuns.responseList,'%9.0f')]);
+switch experiment.paradigm
+    % more decimal places needed on GUI
+    case { 'gapDetection', 'frequencyDiscrimination', 'forwardMaskingD'}
+        message2= ([stimulusParameters.WRVname  ...
+            ':       ' num2str(withinRuns.levelList,'%7.3f')]);
+        message3= (['Thresh (logistic mean):   ' ...
+            num2str(withinRuns.thresholdEstimateTrack,'%7.3f')]);
+    otherwise
+        message2= ([stimulusParameters.WRVname ':      ' ...
+            num2str(withinRuns.levelList,'%7.1f')]);
+        message3= (['Thresh (logistic mean):   ' ...
+            num2str(withinRuns.thresholdEstimateTrack,'%7.1f')]);
+end
+
+addToMsg(str2mat(message1, message2, message3), 0)
+
+% -----------------------------------------------------runCompleted
+function runCompleted(handles)
+% Used at the end of each run
+global experiment stimulusParameters betweenRuns withinRuns
+global rareEvent expGUIhandles
+% disp('run completed')
+
+experiment.status='runCompleted';
+
+plotProgressThisTrial(handles)
+
+switch experiment.ear
+    case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
+            'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
+        % no changes required if model used
+    otherwise
+        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.pushbuttonGO,'visible','off')
+end
+
+if isnan(withinRuns.forceThreshold)
+    % the experiment has been aborted for some reason
+    threshold=withinRuns.forceThreshold;
+    stdev=NaN;
+    logistic.bestK=NaN;
+    logistic.bestThreshold=NaN;
+    medianThreshold=NaN;
+    meanThreshold=NaN;
+else
+    % use only phase 2 levels and responses for calculating thresholds
+    withinRuns.levelsPhaseTwo=...
+        withinRuns.levelList(withinRuns.beginningOfPhase2:end);
+    withinRuns.responsesPhaseTwo=...
+        withinRuns.responseList(withinRuns.beginningOfPhase2:end);
+    [psy, levelsPhaseTwoBinVector, logistic, rareEvent]= ...
+        bestFitPsychometicFunctions...
+        (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo);
+    
+    % plot final psychometric function
+    axes(expGUIhandles.axes5),cla
+    hold on, plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
+    hold on, plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
+    % organise data as psychometric function
+    [psy, levelsBinVector, binFrequencies]= ...
+        psychometricFunction(withinRuns.levelsPhaseTwo,...
+        withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
+    %   point by point with circles of appropiate weighted size
+    hold on,
+    for i=1:length(psy)
+        plot(levelsBinVector(i), psy(i), 'ro', ...
+            'markersize', 50*binFrequencies(i)/sum(binFrequencies))
+    end
+
+    
+    % experimental
+    medianThreshold=median(withinRuns.levelsPhaseTwo);
+    warning off
+    meanThreshold=mean(withinRuns.levelsPhaseTwo);
+    
+    % identify the current threshold estimate
+    switch experiment.paradigm
+        case 'discomfort'
+            % most recent value (not truely a mean value)
+            threshold=withinRuns.levelList(end);
+            stdev=NaN;            
+        otherwise
+            switch experiment.threshEstMethod
+                case {'MaxLikelihood', 'oneIntervalUpDown'}
+                    % last value in the list
+%                     threshold=withinRuns.meanEstTrack(end);
+                    threshold=withinRuns.thresholdEstimateTrack(end);
+                    stdev=NaN;
+                    
+                case {'2I2AFC++', '2I2AFC+++'}
+                    % use peaks and troughs
+                    try		% there may not be enough values to use
+                        peaksUsed=experiment.peaksUsed;
+                        threshold=...
+                            mean(...
+                            [withinRuns.peaks(end-peaksUsed+1:end) ...
+                            withinRuns.troughs(end-peaksUsed+1:end)]);
+                        stdev=...
+                            std([withinRuns.peaks(end-peaksUsed +1:end) ...
+                            withinRuns.troughs(end-peaksUsed:end)]);
+                    catch
+                        threshold=NaN;
+                        stdev=NaN;
+                    end
+            end
+    end
+end
+
+% Store thresholds
+betweenRuns.thresholds=[betweenRuns.thresholds threshold];
+betweenRuns.thresholds_mean=[betweenRuns.thresholds_mean meanThreshold];
+betweenRuns.thresholds_median=...
+    [betweenRuns.thresholds_median medianThreshold];
+betweenRuns.forceThresholds=...
+    [betweenRuns.forceThresholds withinRuns.forceThreshold];
+
+% count observations after the startup phase for record keeping
+betweenRuns.observationCount=...
+    [betweenRuns.observationCount length(withinRuns.levelList)];
+betweenRuns.timesOfFirstReversals=...
+    [betweenRuns.timesOfFirstReversals withinRuns.beginningOfPhase2];
+betweenRuns.catchTrials=...
+    [betweenRuns.catchTrials withinRuns.catchTrialCount];
+
+% add variable length tracks to cell arrays
+if withinRuns.beginningOfPhase2>0
+    betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=...
+        withinRuns.thresholdEstimateTrack;   
+    betweenRuns.levelTracks{length(betweenRuns.thresholds)}=...
+        withinRuns.levelList(withinRuns.beginningOfPhase2:end);
+    betweenRuns.responseTracks{length(betweenRuns.thresholds)}=...
+        withinRuns.responseList(withinRuns.beginningOfPhase2:end);
+else
+    betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=[];
+    betweenRuns.levelTracks{length(betweenRuns.thresholds)}=[];
+    betweenRuns.responseTracks{length(betweenRuns.thresholds)}=[];
+end
+
+betweenRuns.bestGain=[betweenRuns.bestGain rareEvent.bestGain];
+betweenRuns.bestVMin=[betweenRuns.bestVMin rareEvent.bestVMin];
+betweenRuns.bestPaMin=[betweenRuns.bestPaMin rareEvent.bestPaMindB];
+betweenRuns.bestLogisticM=...
+    [betweenRuns.bestLogisticM logistic.bestThreshold];
+betweenRuns.bestLogisticK=[betweenRuns.bestLogisticK logistic.bestK];
+
+resultsSoFar=[betweenRuns.var1Sequence(betweenRuns.runNumber)'...
+    betweenRuns.var2Sequence(betweenRuns.runNumber)'...
+    betweenRuns.thresholds(betweenRuns.runNumber)'
+    ];
+
+fprintf('%10.3f \t%10.3f \t%10.1f  \n', resultsSoFar')
+
+switch experiment.ear
+    case {'left', 'right', 'diotic', 'dichoticLeft','dichoticRight'}
+        disp(['caught out= ' num2str(betweenRuns.caughtOut)])
+end
+
+% plot history of thresholds in panel 4
+axes(expGUIhandles.axes4), cla
+plotColors='rgbmckywrgbmckyw';
+for i=1:length(betweenRuns.thresholds)
+    faceColor=plotColors(floor(i/length(betweenRuns.variableList1)-.01)+1);
+    switch betweenRuns.variableName1
+        case {'targetFrequency', 'maskerRelativeFrequency'}
+            if min(betweenRuns.var1Sequence)>0
+                %             semilogx(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ...
+                %                 betweenRuns.thresholds,  'o', ...
+                %                 'markerSize', 5,'markerFaceColor',faceColor)
+                semilogx(betweenRuns.var1Sequence(i), ...
+                    betweenRuns.thresholds(i),  'o', ...
+                    'markerSize', 5,'markerFaceColor',faceColor)
+            else
+                plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber),  ...
+                    betweenRuns.thresholds,  'o', ...
+                    'markerSize', 5,'markerFaceColor',faceColor)
+                plot(betweenRuns.var1Sequence(i),  ...
+                    betweenRuns.thresholds(i),  'o', ...
+                    'markerSize', 5,'markerFaceColor',faceColor)
+            end
+        otherwise
+            %         plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber),  ...
+            %             betweenRuns.thresholds,  'o', 'markerSize', 5,...
+            %             'markerFaceColor',faceColor)
+            plot(betweenRuns.var1Sequence(i),  ...
+                betweenRuns.thresholds(i),  'o', 'markerSize', 5,...
+                'markerFaceColor',faceColor)
+    end
+    hold on
+end
+xlimRM([ min(betweenRuns.variableList1) max(betweenRuns.variableList1) ])
+ylim(stimulusParameters.WRVlimits)
+ylabel('thresholds')
+xlabel(betweenRuns.variableName1)
+set(gca,'ytick', [0 20 40 60 80 100])
+try
+    % problems if only one x value
+    set(gca,'XTick', sort(betweenRuns.variableList1))
+catch
+end
+grid on, set(gca,'XMinorGrid', 'off')
+
+% If comparison data is available in pearmeter file, plot it now
+if ~isempty (experiment.comparisonData)
+    comparisonData=experiment.comparisonData(:,1:end-1); % ignore final BF
+    [x, ncols]=size(comparisonData);
+    if  length(betweenRuns.variableList1)==ncols
+        hold on
+        plot (sort(betweenRuns.variableList1), comparisonData, 'r')
+        hold off
+    end
+end
+
+% End of the Experiment also?
+if betweenRuns.runNumber==length(betweenRuns.var1Sequence)
+    % yes, end of experiment
+    fileName=['savedData/' experiment.name experiment.date ...
+        experiment.paradigm];
+    % 	save (fileName, 'experiment', 'stimulusParameters', 'betweenRuns', 'withinRuns', 'variableNames', 'paradigmNames', 'LevittControl')
+    disp('Experiment completed')
+    
+    % update subject GUI to acknowledge end of run
+    subjGUImsg=[{'Experiment completed'}, {' '}, {'Thank you!'}];
+    set(handles.textMSG,'string', subjGUImsg   )
+    % play 'Tada'
+    [y,fs,nbits]=wavread('TADA.wav');
+    musicGain=10^(stimulusParameters.musicLeveldB/20);
+    y=y*musicGain;
+    wavplay(y/100,fs, 'async')
+    
+    % update experimenter GUI
+    addToMsg('Experiment completed.',1)
+    
+    printReport
+    experiment.status='endOfExperiment';  
+    return
+else
+    % No, hang on.
+    switch experiment.ear
+        case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
+                'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
+            % no changes required if model used
+        otherwise
+            % decrement catchTrialRate towards baseRate
+            stimulusParameters.catchTrialRate=...
+                stimulusParameters.catchTrialBaseRate + ...
+                (stimulusParameters.catchTrialRate...
+                -stimulusParameters.catchTrialBaseRate)...
+                *(1-exp(-stimulusParameters.catchTrialTimeConstant));
+            fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
+                stimulusParameters.catchTrialRate)
+            
+            % and go again
+            set(handles.pushbuttonGO,'backgroundcolor','y') 
+            set(handles.frame1,'visible','off')
+            set(handles.pushbuttonGO,'visible','on')
+            msg=[{'Ready to start new trial'}, {' '},...
+                {'Please,click on the GO button'}];
+            set(handles.textMSG,'string',msg)
+    end
+    experiment.status='waitingForGO';
+    %     fprintf('\n')
+    
+    [y,fs,nbits]=wavread('CHIMES.wav');
+    musicGain=10^(stimulusParameters.musicLeveldB/20);
+    y=y*musicGain;
+    wavplay(y/100,fs,'async')
+end
+
+% -----------------------------------------------------MAPmodelRunsGUI
+% The computer presses the buttons
+function 	MAPmodelRunsGUI(handles)
+global experiment stimulusParameters method expGUIhandles
+global AN_IHCsynapseParams
+method=[];
+
+while strcmp(experiment.status,'waitingForGO') 
+    % no catch trials for MAP model
+    experiment.allowCatchTrials=0;
+    
+    % initiates run and plays first stimulus and it returns 
+    %  without waiting for button press
+    startNewRun(handles)	
+
+    if sum(strcmp(experiment.ear,...
+            {'MAPmodelMultiCh', 'MAPmodelListen'}))
+        % use BFlist specified in MAPparams file
+        BFlist= -1;
+    else
+        BFlist=stimulusParameters.targetFrequency;
+    end
+    showParams=0;
+    %  find model parameters using the 'name' box (e.g. CTa ->MAPparamsCTa)
+    paramFunctionName=['method=MAPparams' experiment.name ...
+        '(BFlist, stimulusParameters.sampleRate, showParams);'];
+    eval(paramFunctionName) % go and fetch the parameters
+    
+
+    % show sample Rate on GUI; it must be set in MAPparams
+    set(expGUIhandles.textsampleRate,'string',...
+        num2str(stimulusParameters.sampleRate))
+    
+    if experiment.singleShot
+%         AN_IHCsynapseParams.showSummaryStatistics=1;
+        method.showSummaryStatistics=1;
+        AN_IHCsynapseParams.plotSynapseContents=1;
+    else
+        method.showSummaryStatistics=0;
+        AN_IHCsynapseParams.plotSynapseContents=0;
+    end
+    
+    if strcmp(experiment.ear, 'MAPmodelSingleCh')
+    method.MGmembranePotentialSave=1;
+    end
+    
+    % continuous loop until the program stops itself
+    while strcmp(experiment.status,'waitingForResponse')
+        %  NB at this point the stimulus has been played
+        pause(0.1)  % to allow interrupt with CTRL/C
+        
+        switch experiment.ear
+            case { 'MAPmodelListen'}
+            set(handles.pushbutton1,'backgroundcolor','y','visible','on')
+            set(handles.pushbutton2,'backgroundcolor','y','visible','on')
+        end
+
+AN_IHCsynapseParams.mode=	'spikes';
+
+% Analayse the current stimulus using MAP
+        [modelResponse earObject]= MAPmodel( experiment.MAPplot, method);
+        
+        if experiment.stop || experiment.singleShot
+            % trap for single trial or user interrupt using 'stop' button.
+            experiment.status= 'waitingForStart';
+            experiment.stop=0;
+            addToMsg('manually stopped',1);
+            return
+        end
+        
+        switch modelResponse
+            case 1
+                %     userDoesNotHearTarget(handles)
+                switch experiment.ear
+                    case {'MAPmodelListen'}
+                        % illuminate appropriate button
+                        set(handles.pushbutton1,...
+                            'backgroundcolor','r','visible','on')
+                        set(handles.pushbutton2,'backgroundcolor','y')
+                end
+                userDecides(handles, false)
+                if experiment.singleShot, return, end
+
+            case 2
+                %   userHearsTarget(handles)
+                switch experiment.ear
+                    case {'MAPmodelListen'}
+                        % illuminate appropriate button (DEMO only)
+                        set(handles.pushbutton2,'backgroundcolor',...
+                            'r','visible','on')
+                        set(handles.pushbutton1,'backgroundcolor','y')
+                end
+                
+                switch experiment.paradigm
+                    case 'discomfort'
+                        % always treat discomfort as 'not heard'
+                        userDecides(handles, false)
+                    otherwise
+                        userDecides(handles, true)
+                end
+            otherwise
+                % probably an abort
+                return
+        end
+    end
+end
+
+function [modelResponse, MacGregorResponse]=MAPmodel( MAPplot, method)
+
+global experiment stimulusParameters audio withinRuns
+global outerMiddleEarParams DRNLParams AN_IHCsynapseParams
+
+savePath=path;
+addpath(['..' filesep 'MAP'], ['..' filesep 'utilities'])
+modelResponse=[];
+MacGregorResponse=[];
+
+% mono only (column vector)
+audio=audio(:,1)';
+
+% if stop button pressed earlier
+if experiment.stop, return, end
+
+% -------------------------------------------------------------- run Model
+MAPparamsName=experiment.name;
+showPlotsAndDetails=experiment.MAPplot;
+AN_spikesOrProbability='spikes';
+
+% [response, method]=MAPsequenceSeg(audio, method, 1:8);
+global ICoutput ANdt
+    MAP1_14(audio, 1/method.dt, method.nonlinCF,...
+        MAPparamsName, AN_spikesOrProbability);
+    
+if showPlotsAndDetails
+    options.printModelParameters=0;
+    options.showModelOutput=1;
+    options.printFiringRates=1;
+    options.showACF=0;
+    options.showEfferent=1;
+    options.surfProbability=0;
+    showMapOptions.surfSpikes=0;
+    UTIL_showMAP(options)
+end
+
+% No response,  probably caused by hitting 'stop' button
+if isempty(ICoutput), return, end
+
+% MacGregor response is the sum total of all final stage spiking
+MacGregorResponse= sum(ICoutput,1);                 % use IC
+
+% ---------------------------------------------------------- end model run
+
+dt=ANdt;
+time=dt:dt:dt*length(MacGregorResponse);
+
+% group delay on unit response
+MacGonsetDelay= 0.004;
+MacGoffsetDelay= 0.022;
+
+% now find the response of the MacGregor model during the target presentation + group delay
+switch experiment.threshEstMethod
+    case {'2I2AFC++', '2I2AFC+++'}
+        idx= time>stimulusParameters.testTargetBegins+MacGonsetDelay ...
+            & time<stimulusParameters.testTargetEnds+MacGoffsetDelay;
+        nSpikesTrueWindow=sum(MacGregorResponse(:,idx));
+        idx=find(time>stimulusParameters.testNonTargetBegins+MacGonsetDelay ...
+            & time<stimulusParameters.testNonTargetEnds+MacGoffsetDelay);
+        nSpikesFalseWindow=sum(MacGregorResponse(:,idx));
+        % nSpikesDuringTarget is +ve when more spikes are found
+        %   in the target window
+        difference= nSpikesTrueWindow-nSpikesFalseWindow;
+
+        if difference>0
+            % hit
+            nSpikesDuringTarget=experiment.MacGThreshold+1;
+        elseif    difference<0
+            % miss (wrong choice)
+            nSpikesDuringTarget=experiment.MacGThreshold-1;
+        else
+            if rand>0.5
+                % hit (random choice)
+                nSpikesDuringTarget=experiment.MacGThreshold+1;
+            else
+                % miss (random choice)
+                nSpikesDuringTarget=experiment.MacGThreshold-1;
+            end
+        end
+        disp(['level target dummy decision: ' ...
+            num2str([withinRuns.variableValue nSpikesTrueWindow ...
+            nSpikesFalseWindow  nSpikesDuringTarget], '%4.0f') ] )
+
+    otherwise
+        % idx=find(time>stimulusParameters.testTargetBegins+MacGonsetDelay ...
+        %         & time<stimulusParameters.testTargetEnds+MacGoffsetDelay);
+        % no delay at onset
+        idx=find(time>stimulusParameters.testTargetBegins +MacGonsetDelay...
+            & time<stimulusParameters.testTargetEnds+MacGoffsetDelay);
+        nSpikesDuringTarget=sum(MacGregorResponse(:,idx));
+        
+        % find(MacGregorResponse)*dt-stimulusParameters.stimulusDelay
+        timeX=time(idx);
+end
+
+% now find the response of the MacGregor model at the end of the masker
+idx2=find(time>stimulusParameters.testTargetBegins-0.02 ...
+    & time<stimulusParameters.testTargetBegins);
+if ~isempty(idx2)
+    maskerRate=mean(mean(MacGregorResponse(idx2)));
+else
+    %e.g. no masker
+    maskerRate=0;
+end
+
+if experiment.MAPplot
+    % add vertical lines to indicate target region
+    figure(99), subplot(6,1,6)
+    hold on
+    yL=get(gca,'YLim');
+    plot([stimulusParameters.testTargetBegins + MacGonsetDelay ...
+        stimulusParameters.testTargetBegins   + MacGonsetDelay],yL,'r')
+    plot([stimulusParameters.testTargetEnds   + MacGoffsetDelay ...
+        stimulusParameters.testTargetEnds     + MacGoffsetDelay],yL,'r')
+end
+
+% specify unambiguous response
+switch experiment.paradigm
+    case 'gapDetection'
+        gapResponse=(maskerRate-nSpikesDuringTarget)/maskerRate;
+        if gapResponse>0.2
+            modelResponse=2;    % gap detected
+        else
+            modelResponse=1;    % gap not detected
+        end
+        [nSpikesDuringTarget maskerRate gapResponse modelResponse]
+        figure(22), plot(timeX,earObject(idx))
+    otherwise
+        if nSpikesDuringTarget>experiment.MacGThreshold
+            modelResponse=2;    % stimulus detected
+        else
+            modelResponse=1;    % nothing heard (default)
+        end
+end
+
+
+path(savePath)
+
+% -----------------------------------------------------statsModelRunsGUI
+% The computer presses the buttons
+function 	statsModelRunsGUI(handles)
+% Decision are made at random using a prescribe statistical function
+% to set probabilities as a function of signal level.
+global experiment
+
+experiment.allowCatchTrials=0;
+
+while strcmp(experiment.status,'waitingForGO')
+    % i.e. waiting for new run
+    if experiment.stop
+        % user has requested an abort
+        experiment.status= 'waitingForStart';
+        addToMsg('manually stopped',1)
+        return
+    end
+    
+    % initiates run and plays first stimulus and it returns
+    %  without waiting for button press
+    % NB stimulus is not actually generated (for speed)
+    startNewRun(handles)
+    
+    while strcmp(experiment.status,'waitingForResponse')
+        % create artificial response here
+        modelResponse=statsModelGetResponse;
+        switch modelResponse
+            case 1
+                %                 userDoesNotHearTarget(handles)
+                userDecides(handles, false)
+            case 2
+                %                 userHearsTarget(handles)
+                userDecides(handles, true)
+        end
+    end
+end
+
+% -----------------------------------------------------statsModelGetResponse
+function modelResponse=statsModelGetResponse(handles)
+global experiment  withinRuns  statsModel stimulusParameters
+% use the generating function to decide if a detection occurs or not
+
+% pause(0.1)  % to allow stopping with CTRL/C but slows things down
+
+% first compute the probability that a detection occurs
+switch experiment.ear
+    case {'statsModelLogistic'}
+        prob= 1./(1+exp(-statsModel.logisticSlope.*(withinRuns.variableValue-statsModel.logisticMean)));
+        %         if experiment.psyFunSlope<0,
+        %             prob=1-prob;
+        %         end
+        
+    case 'statsModelRareEvent'
+        if experiment.psyFunSlope<0
+            addToMsg('statsModelRareEvent cannot be used with negative slope',0)
+            error('statsModelRareEvent cannot be used with negative slope')
+        end
+        
+        % standard formula is prob = 1 – exp(-d (g P – A))
+        % here A->A;  To find Pmin use A/gain
+        pressure=28*10^(withinRuns.variableValue/20);
+        gain=statsModel.rareEvenGain;
+        A=statsModel.rareEventVmin;
+        d=stimulusParameters.targetDuration;
+        gP_Vmin=gain*pressure-A;
+        if gP_Vmin>0
+            prob=1-exp(-d*(gP_Vmin));
+        else
+            prob=0;
+        end
+end
+
+% Use the probability to choose whether or not a detection has occurred
+switch experiment.threshEstMethod
+    case {'MaxLikelihood', 'oneIntervalUpDown'}
+        if rand<prob
+            modelResponse=2; %bingo
+        else
+            modelResponse=1; %nothing heard
+        end
+        
+    case {'2I2AFC++', '2I2AFC+++'}
+        if rand<prob
+            modelResponse=2; %bingo
+        else %if the stimulus is not audible, take a 50:50 chance of getting it right
+            if rand<0.5
+                modelResponse=2; %bingo
+            else
+                modelResponse=1; %nothing heard
+            end
+        end
+end
+
+
+% ------------------------------------------------------- printTabTable
+function printTabTable(M, headers)
+% printTabTable prints a matrix as a table with tabs
+%headers are optional
+%headers=strvcat('firstname', 'secondname')
+%  printTabTable([1 2; 3 4],strvcat('a1','a2'));
+
+if nargin>1
+    [r c]=size(headers);
+    for no=1:r
+        fprintf('%s\t',headers(no,:))
+    end
+    fprintf('\n')
+end
+
+[r c]=size(M);
+
+for row=1:r
+    for col=1:c
+        if row==1 && col==1 && M(1,1)==-1000
+            %   Print nothing (tab follows below)
+        else
+            fprintf('%s',num2str(M(row,col)))
+        end
+        if col<c
+            fprintf('\t')
+        end
+    end
+    fprintf('\n')
+end
+
+% ------------------------------------------------------- xlimRM
+function xlimRM(x)
+try
+    xlim([x(1) x(2)])
+catch
+end
+
+% ------------------------------------------------------- ylimRM
+function ylimRM(x)
+try
+    ylim([x(1) x(2)])
+catch
+end
+
+
+function editdigitInput_CreateFcn(hObject, eventdata, handles)
+
+% Hint: edit controls usually have a white background on Windows.
+%       See ISPC and COMPUTER.
+if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
+    set(hObject,'BackgroundColor','white');
+end
+
+
+% -----------------------------------------------------buttonBoxIntitialize
+function buttonBoxIntitialize
+% initialize button box
+global  serobj
+try
+    fclose(serobj);
+catch
+end
+
+try
+    serobj = serial('COM4') ;           	% Creating serial port object now its connected to COM4 !!! button boxes in booths are connected to COM2
+    serobj.Baudrate = 9600;           		% Set the baud rate at the specific value
+    set(serobj, 'Parity', 'none') ;     	% Set parity as none
+    set(serobj, 'Databits', 8) ;          	% set the number of data bits
+    set(serobj, 'StopBits', 1) ;         	% set number of stop bits as 1
+    set(serobj, 'Terminator', 'CR') ; 		% set the terminator value to carriage return
+    set(serobj, 'InputBufferSize', 512) ;  	% Buffer for read operation, default it is 512
+    set(serobj,'timeout',10);           	% 10 sec timeout on button press
+    set(serobj, 'ReadAsyncMode', 'continuous')
+    set(serobj, 'BytesAvailableFcn', @buttonBox_callback)
+    set(serobj, 'BytesAvailableFcnCount', 1)
+    set(serobj, 'BytesAvailableFcnMode', 'byte')
+    % set(serobj, 'BreakInterruptFcn', '@buttonBox_Calback')
+    
+    fopen(serobj);
+    buttonBoxStatus=get(serobj,'status');
+catch
+    disp('** no button box found - use mouse **')
+end