Skip to content
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
# exclude content of logfiles folders
*.tsv
*.mat
check_my_code_report.txt
17 changes: 17 additions & 0 deletions checkAbort.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function checkAbort(cfg)
% Check for experiment abortion from operator

[keyIsDown, ~, keyCode] = KbCheck(cfg.keyboard);

if keyIsDown && keyCode(KbName(cfg.escapeKey))

global stopEverything
stopEverything = true;

cleanUp();

error('Escape key press detected: aborting experiment.')

end

end
12 changes: 4 additions & 8 deletions CPP_getResponseDemo.m → demos/CPP_getResponseDemo.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
% (a wrapper around the KbQueue function from PTB)

% start with a clean slate
cd ..
clear; clc;
if IsOctave
more off % for a better display experience
Expand All @@ -29,6 +30,8 @@
cfg.keyboard = [];
cfg.responseBox = [];

cfg.escapeKey = 'ESCAPE';

% We set which keys are "valid", any keys other than those will be ignored
expParameters.responseKey = {};

Expand Down Expand Up @@ -66,7 +69,6 @@
end



%% Run demo

% Create the keyboard queue to collect responses.
Expand All @@ -77,15 +79,11 @@
startSecs = GetSecs();
getResponse('start', cfg, expParameters, 1);



% Here we wait for 5 seconds but are still collecting responses.
% So you could still be doing something else (presenting audio and visual stim) and
% still collect responses.
WaitSecs(5);



% Check what keys were pressed (all of them)
responseEvents = getResponse('check', cfg, expParameters, 0);

Expand All @@ -99,8 +97,6 @@
getResponse('stop', cfg, expParameters, 1);




%% Now we look what keys were pressed and when
for iEvent = 1:size(responseEvents, 1)

Expand All @@ -110,7 +106,7 @@
eventType = 'released';
end

fprintf('%s was %s at time %.3f seconds\n', ...
fprintf('\n%s was %s at time %.3f seconds\n', ...
responseEvents(iEvent).key_name, ...
eventType, ...
responseEvents(iEvent).onset - startSecs);
Expand Down
126 changes: 66 additions & 60 deletions getResponse.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
% - flush:
% - stop:
%
% - getOnlyPress: if set to 1 the function will only return the key presses and
% will not return when the keys were released (default=1)
% - getOnlyPress: if set to true the function will only return the key presses and
% will not return when the keys were released (default=true)
% See the section on OUTPUT below for more info
%
%
Expand All @@ -44,56 +44,25 @@


if nargin < 4
getOnlyPress = 1;
getOnlyPress = true;
end

responseEvents = struct;
responseEvents.onset = [];
responseEvents.trial_type = [];
responseEvents.duration = [];
responseEvents.key_name = [];
responseEvents.pressed = [];

responseBox = cfg.responseBox;

switch action

case 'init'

% Prevent spilling of keystrokes into console. If you use ListenChar(2)
% this will prevent you from using KbQueue.
% Prevent spilling of keystrokes into console.
% If you use ListenChar(2), this will prevent you from using KbQueue.
ListenChar(-1);

% Clean and realease any queue that might be opened
KbQueueRelease(responseBox);

%% Defines keys
% list all the response keys we want KbQueue to listen to

% by default we listen to all keys
% but if responseKey is set in the parameters we override this
keysOfInterest = ones(1,256);

fprintf('\n Will be listening for key presses on : ')

if isfield(expParameters, 'responseKey') && ~isempty(expParameters.responseKey)

keysOfInterest = zeros(1,256);

for iKey = 1:numel(expParameters.responseKey)
fprintf('\n - %s ', expParameters.responseKey{iKey})
responseTargetKeys(iKey) = KbName(expParameters.responseKey(iKey)); %#ok<*SAGROW>
end

keysOfInterest(responseTargetKeys) = 1;

else

fprintf('ALL KEYS.')

end

fprintf('\n\n')
keysOfInterest = setKeysOfInterest(expParameters);

% Create the keyboard queue to collect responses.
KbQueueCreate(responseBox, keysOfInterest);
Expand All @@ -106,29 +75,10 @@

case 'check'

iEvent = 1;

while KbEventAvail(responseBox)

event = KbEventGet(responseBox);

% we only return the pressed keys by default
if getOnlyPress && event.Pressed==0
else

responseEvents(iEvent,1).onset = event.Time;
responseEvents(iEvent,1).trial_type = 'response';
responseEvents(iEvent,1).duration = 0;
responseEvents(iEvent,1).key_name = KbName(event.Keycode);
responseEvents(iEvent,1).pressed = event.Pressed;

end

iEvent = iEvent + 1;

end

responseEvents = getAllKeyEvents(responseEvents, responseBox, getOnlyPress);

checkAbort(cfg)

case 'flush'

KbQueueFlush(responseBox);
Expand All @@ -146,6 +96,62 @@

talkToMe(action, expParameters);

end


function keysOfInterest = setKeysOfInterest(expParameters)
% list all the response keys we want KbQueue to listen to
% by default we listen to all keys
% but if responseKey is set in the parameters we override this

keysOfInterest = ones(1,256);

fprintf('\n Will be listening for key presses on : ')

if isfield(expParameters, 'responseKey') && ~isempty(expParameters.responseKey)

responseTargetKeys = nan(1,numel(expParameters.responseKey));

for iKey = 1:numel(expParameters.responseKey)
fprintf('\n - %s ', expParameters.responseKey{iKey})
responseTargetKeys(iKey) = KbName(expParameters.responseKey(iKey));
end

keysOfInterest(responseTargetKeys) = 1;

else

fprintf('ALL KEYS.')

end

fprintf('\n\n')
end


function responseEvents = getAllKeyEvents(responseEvents, responseBox, getOnlyPress)

iEvent = 1;

while KbEventAvail(responseBox)

event = KbEventGet(responseBox);

% we only return the pressed keys by default
if getOnlyPress==true && event.Pressed==0
else

responseEvents(iEvent,1).onset = event.Time;
responseEvents(iEvent,1).trial_type = 'response';
responseEvents(iEvent,1).duration = 0;
responseEvents(iEvent,1).key_name = KbName(event.Keycode);
responseEvents(iEvent,1).pressed = event.Pressed;

iEvent = iEvent + 1;

end

end

end

Expand Down Expand Up @@ -182,4 +188,4 @@ function talkToMe(action, expParameters)

end

end
end
54 changes: 54 additions & 0 deletions initPTB.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,62 @@

%% Audio
% Intialize PsychPortAudio
% in setParameters, one needs to define
% cfg.audio.channels
% cfg.fs
% cfg.PTBInitVolume


InitializePsychSound(1);

if any(strcmp(cfg.stimComp,{'mac','linux'}))

% pahandle = PsychPortAudio('Open' [, deviceid][, mode][, reqlatencyclass][, freq] ...
% [, channels][, buffersize][, suggestedLatency][, selectchannels][, specialFlags=0]);
% Try to get the lowest latency that is possible under the constraint of reliable playback
cfg.pahandle = PsychPortAudio('Open', [], [], 3, cfg.fs, cfg.audio.channels);

else

% get audio device list
audio_dev = PsychPortAudio('GetDevices');

% find output device using WASAPI deiver
idx = find([audio_dev.NrInputChannels] == 0 & ...
[audio_dev.NrOutputChannels] == 2 & ...
~cellfun(@isempty, regexp({audio_dev.HostAudioAPIName},'WASAPI')));

% save device ID
cfg.audio.i = audio_dev(idx).DeviceIndex;

% get device's sampling rate
cfg.fs = audio_dev(idx).DefaultSampleRate;

% the latency is not important - but consistent latency is! Let's try with WASAPI driver.
cfg.pahandle = PsychPortAudio('Open', cfg.audio.i, 1, 3, cfg.fs, cfg.audio.channels);
% cfg.pahandle = PsychPortAudio('Open', [], [], 0, cfg.fs, cfg.audio.channels);

end

% set initial PTB volume for safety (participants can adjust this manually
% at the begining of the experiment)
PsychPortAudio('Volume', cfg.pahandle, cfg.PTBInitVolume);

cfg.audio.pushsize = cfg.fs*0.010; %! push N ms only
cfg.requestoffsettime = 1; % offset 1 sec
cfg.reqsampleoffset = cfg.requestoffsettime*cfg.fs; %


% playing parameters
% sound repetition
cfg.PTBrepet = 1;

% Start immediately (0 = immediately)
cfg.PTBstartCue = 0;

% Should we wait for the device to really start (1 = yes)
cfg.PTBwaitForDevice = 1;


%% Visual

Expand Down