From 9c45e6b95e7e7a204c1e6cf25d2d476ce3e64f3c Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 16 Jul 2020 22:45:23 +0200 Subject: [PATCH 1/9] refactor set keys of interest --- getResponse.m | 57 +++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/getResponse.m b/getResponse.m index 265f2b3..7304318 100644 --- a/getResponse.m +++ b/getResponse.m @@ -67,33 +67,7 @@ % 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); @@ -183,3 +157,32 @@ function talkToMe(action, expParameters) end 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 \ No newline at end of file From aace529ccfe309c48f6ca07d100fe291c3b0d623 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 16 Jul 2020 22:45:56 +0200 Subject: [PATCH 2/9] refactor get all key events --- getResponse.m | 50 +++++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/getResponse.m b/getResponse.m index 7304318..1544831 100644 --- a/getResponse.m +++ b/getResponse.m @@ -80,27 +80,7 @@ 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); case 'flush' @@ -185,4 +165,32 @@ function talkToMe(action, expParameters) 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 \ No newline at end of file From 536ff16b63918dad8de57070f63fe306e23c2b97 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 16 Jul 2020 22:46:17 +0200 Subject: [PATCH 3/9] clean getResponse --- CPP_getResponseDemo.m | 2 +- getResponse.m | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/CPP_getResponseDemo.m b/CPP_getResponseDemo.m index b276cc2..d1968d8 100644 --- a/CPP_getResponseDemo.m +++ b/CPP_getResponseDemo.m @@ -110,7 +110,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); diff --git a/getResponse.m b/getResponse.m index 1544831..8a8f797 100644 --- a/getResponse.m +++ b/getResponse.m @@ -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 % % @@ -44,15 +44,10 @@ 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; @@ -60,8 +55,8 @@ 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 @@ -138,6 +133,7 @@ function 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 From 1fbe08b3d439099376e0ca19303ac2e11fa9f933 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 16 Jul 2020 23:40:55 +0200 Subject: [PATCH 4/9] Add function to check if user asked to abort experiment --- checkAbort.m | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 checkAbort.m diff --git a/checkAbort.m b/checkAbort.m new file mode 100644 index 0000000..a49232b --- /dev/null +++ b/checkAbort.m @@ -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(); + + warning('\nEscape key press detected: aborting experiment.\n') + +end + +end \ No newline at end of file From 70c30727bb37ca5f9fcf8b249fe029d704fda47d Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 16 Jul 2020 23:41:32 +0200 Subject: [PATCH 5/9] checkAbort called at every getResponse check --- CPP_getResponseDemo.m | 2 ++ getResponse.m | 75 +++++++++++++++++++++---------------------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/CPP_getResponseDemo.m b/CPP_getResponseDemo.m index d1968d8..a2324a6 100644 --- a/CPP_getResponseDemo.m +++ b/CPP_getResponseDemo.m @@ -29,6 +29,8 @@ cfg.keyboard = []; cfg.responseBox = []; +cfg.escapeKey = 'Escape'; + % We set which keys are "valid", any keys other than those will be ignored expParameters.responseKey = {}; diff --git a/getResponse.m b/getResponse.m index 8a8f797..c81ae88 100644 --- a/getResponse.m +++ b/getResponse.m @@ -77,6 +77,7 @@ responseEvents = getAllKeyEvents(responseEvents, responseBox, getOnlyPress); + checkAbort(cfg) case 'flush' @@ -95,42 +96,6 @@ talkToMe(action, expParameters); - -end - - -function talkToMe(action, expParameters) - -if ~isfield(expParameters, 'verbose') || isempty(expParameters.verbose) - expParameters.verbose = false; -end - -switch action - - case 'init' - - case 'start' - - fprintf('\n starting to listen to keypresses\n') - - case 'check' - - if expParameters.verbose - fprintf('\n checking recent keypresses\n') - end - - case 'flush' - - if expParameters.verbose - fprintf('\n reinitialising keyboard queue\n') - end - - case 'stop' - - fprintf('\n stopping to listen to keypresses\n\n') - -end - end @@ -144,7 +109,7 @@ function talkToMe(action, expParameters) 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) @@ -164,7 +129,6 @@ function talkToMe(action, expParameters) end - function responseEvents = getAllKeyEvents(responseEvents, responseBox, getOnlyPress) iEvent = 1; @@ -189,4 +153,39 @@ function talkToMe(action, expParameters) end +end + + +function talkToMe(action, expParameters) + +if ~isfield(expParameters, 'verbose') || isempty(expParameters.verbose) + expParameters.verbose = false; +end + +switch action + + case 'init' + + case 'start' + + fprintf('\n starting to listen to keypresses\n') + + case 'check' + + if expParameters.verbose + fprintf('\n checking recent keypresses\n') + end + + case 'flush' + + if expParameters.verbose + fprintf('\n reinitialising keyboard queue\n') + end + + case 'stop' + + fprintf('\n stopping to listen to keypresses\n\n') + +end + end \ No newline at end of file From 481b2229c7d3defbd416a1855fb3a6379446b5c7 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 16 Jul 2020 23:56:42 +0200 Subject: [PATCH 6/9] make checkAbort throw an error --- .gitignore | 1 + CPP_getResponseDemo.m | 9 +-------- checkAbort.m | 2 +- getResponse.m | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 638e3cc..a0a4806 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ # exclude content of logfiles folders *.tsv *.mat +check_my_code_report.txt \ No newline at end of file diff --git a/CPP_getResponseDemo.m b/CPP_getResponseDemo.m index a2324a6..c72a807 100644 --- a/CPP_getResponseDemo.m +++ b/CPP_getResponseDemo.m @@ -29,7 +29,7 @@ cfg.keyboard = []; cfg.responseBox = []; -cfg.escapeKey = 'Escape'; +cfg.escapeKey = 'ESCAPE'; % We set which keys are "valid", any keys other than those will be ignored expParameters.responseKey = {}; @@ -68,7 +68,6 @@ end - %% Run demo % Create the keyboard queue to collect responses. @@ -79,15 +78,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); @@ -101,8 +96,6 @@ getResponse('stop', cfg, expParameters, 1); - - %% Now we look what keys were pressed and when for iEvent = 1:size(responseEvents, 1) diff --git a/checkAbort.m b/checkAbort.m index a49232b..d2107a8 100644 --- a/checkAbort.m +++ b/checkAbort.m @@ -10,7 +10,7 @@ function checkAbort(cfg) cleanUp(); - warning('\nEscape key press detected: aborting experiment.\n') + error('Escape key press detected: aborting experiment.') end diff --git a/getResponse.m b/getResponse.m index c81ae88..c8f1eeb 100644 --- a/getResponse.m +++ b/getResponse.m @@ -78,7 +78,7 @@ responseEvents = getAllKeyEvents(responseEvents, responseBox, getOnlyPress); checkAbort(cfg) - + case 'flush' KbQueueFlush(responseBox); From b9d6e497084147d07b37e1432a7ab24b00319104 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 17 Jul 2020 09:55:20 +0200 Subject: [PATCH 7/9] create demo folder --- CPP_getResponseDemo.m | 113 ------------------------------------------ 1 file changed, 113 deletions(-) delete mode 100644 CPP_getResponseDemo.m diff --git a/CPP_getResponseDemo.m b/CPP_getResponseDemo.m deleted file mode 100644 index c72a807..0000000 --- a/CPP_getResponseDemo.m +++ /dev/null @@ -1,113 +0,0 @@ -%% Demo showing how to use the getResponse function - -% This small script shows how to use the getReponse function -% (a wrapper around the KbQueue function from PTB) - -% start with a clean slate -clear; clc; -if IsOctave - more off % for a better display experience -end - -%% set parameters - -% cfg.responseBox would be the device number of the device used by the participant to give his/her -% response: like the button box in the scanner or a separate keyboard for a behavioral experiment -% -% cfg.keyboard would be the device number of the keyboard on which the experimenter will type or -% press the keys necessary to start or abort the experiment. - -% cfg.responseBox and cfg.keyboard can be different or the same. - -% If you want to know the device number of all the keyboards and responses -% boxes connected to the computer you can use the following code. -% [cfg.keyboardNumbers, cfg.keyboardNames] = GetKeyboardIndices - -% Using empty vectors should work for linux when to select the "main" -% keyboard. You might have to try some other values for Windows. To -% assigne a specific keyboard input the kb assigned value (see README) -cfg.keyboard = []; -cfg.responseBox = []; - -cfg.escapeKey = 'ESCAPE'; - -% We set which keys are "valid", any keys other than those will be ignored -expParameters.responseKey = {}; - - -%% init - -% Keyboard -% Make sure keyboard mapping is the same on all supported operating systems -% Apple MacOS/X, MS-Windows and GNU/Linux: -KbName('UnifyKeyNames'); - - -% we ask PTB to tell us which keyboard devices are connected to the computer -[cfg.keyboardNumbers, cfg.keyboardNames] = GetKeyboardIndices; - -cfg.keyboardNumbers -cfg.keyboardNames - - -% Test that the keyboards are correctly configured -testKeyboards(cfg); - -% Give the time to the test key to be released and not listened -WaitSecs(1); - - -fprintf('\nDuring the next 5 seconds we will collect responses on the following keys: \n\n'); -if isempty(expParameters.responseKey) - fprintf('\nALL KEYS\n\n'); -else - for iKey=1:numel(expParameters.responseKey) - fprintf('\n%s', expParameters.responseKey{iKey}); - end - fprintf('\n\n'); -end - - -%% Run demo - -% Create the keyboard queue to collect responses. -getResponse('init', cfg, expParameters, 1); - -% Start collecting responses for 5 seconds -% Each new key press is added to the queue of events recorded by KbQueue -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); - -% The following line would only return key presses and not releases -% responseEvents = getResponse('check', cfg, expParameters, 1); - -% This can be used to flush the queue: empty all events that are still present in the queue -getResponse('flush', cfg, expParameters, 1); - -% If you wan to stop listening to key presses. -getResponse('stop', cfg, expParameters, 1); - - -%% Now we look what keys were pressed and when -for iEvent = 1:size(responseEvents, 1) - - if responseEvents(iEvent).pressed - eventType = 'pressed'; - else - eventType = 'released'; - end - - fprintf('\n%s was %s at time %.3f seconds\n', ... - responseEvents(iEvent).key_name, ... - eventType, ... - responseEvents(iEvent).onset - startSecs); - -end From 5e822a9c8e81664708940667d3f1976d233b6295 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 17 Jul 2020 14:13:45 +0200 Subject: [PATCH 8/9] create demo folder --- CPP_getResponseDemo.m => demos/CPP_getResponseDemo.m | 1 + 1 file changed, 1 insertion(+) rename CPP_getResponseDemo.m => demos/CPP_getResponseDemo.m (99%) diff --git a/CPP_getResponseDemo.m b/demos/CPP_getResponseDemo.m similarity index 99% rename from CPP_getResponseDemo.m rename to demos/CPP_getResponseDemo.m index c72a807..5736cbd 100644 --- a/CPP_getResponseDemo.m +++ b/demos/CPP_getResponseDemo.m @@ -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 From 392221f5174b695163fae78b77f6fbebfa39ec32 Mon Sep 17 00:00:00 2001 From: Ceren Date: Sat, 18 Jul 2020 11:05:02 +0200 Subject: [PATCH 9/9] audio adds into initPTB --- initPTB.m | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/initPTB.m b/initPTB.m index 5a1e7c8..ce05478 100644 --- a/initPTB.m +++ b/initPTB.m @@ -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