Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/moxunit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CI

on:
push:
branches:
- master
pull_request:
branches: '*'

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
fetch-depth: 1
- name: MOxUnit Action
uses: joergbrech/moxunit-action@v1.1
with:
tests: tests
src: subfun
with_coverage: true
cover_xml_file: coverage.xml
- name: Code coverage
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
file: coverage.xml # optional
flags: unittests # optional
name: codecov-umbrella # optional
fail_ci_if_error: true # optional (default = false)
30 changes: 15 additions & 15 deletions audioLocTranslational.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,8 @@
[cfg] = initPTB(cfg);

[el] = eyeTracker('Calibration', cfg);

% % % REFACTOR THIS FUNCTION % % %

[cfg] = expDesign(cfg);

cfg.design.blockNames

% % % REFACTOR THIS FUNCTION % % %
[cfg] = expDesign(cfg);

% Prepare for the output logfiles with all
logFile.extraColumns = cfg.extraColumns;
Expand All @@ -69,7 +63,7 @@

getResponse('start', cfg.keyboard.responseBox);

WaitSecs(cfg.timing.onsetDelay);
waitFor(cfg, cfg.timing.onsetDelay);

%% For Each Block

Expand All @@ -90,13 +84,19 @@
thisEvent.direction = cfg.design.directions(iBlock, iEvent);
% thisEvent.speed = cfg.design.speeds(iBlock, iEvent);
thisEvent.target = cfg.design.fixationTargets(iBlock, iEvent);

% we wait for a trigger every 2 events
if cfg.pacedByTriggers.do && mod(iEvent, 2) == 1
waitForTrigger( ...
cfg, ...
cfg.keyboard.responseBox, ...
cfg.pacedByTriggers.quietMode, ...
cfg.pacedByTriggers.nbTriggers);
end

% % % REFACTOR THIS FUNCTION % % %

% play the sounds and collect onset and duration of the event
[onset, duration] = doAudMot(cfg, thisEvent);

% % % REFACTOR THIS FUNCTION % % %
[onset, duration] = doAuditoryMotion(cfg, thisEvent);

thisEvent.event = iEvent;
thisEvent.block = iBlock;
Expand All @@ -122,13 +122,13 @@
saveResponsesAndTriggers(responseEvents, cfg, logFile, triggerString);

% wait for the inter-stimulus interval
WaitSecs(cfg.timing.ISI);
waitFor(cfg, cfg.timing.ISI);

end

eyeTracker('StopRecordings', cfg);

WaitSecs(cfg.timing.IBI);
waitFor(cfg, cfg.timing.IBI);

% trigger monitoring
triggerEvents = getResponse('check', cfg.keyboard.responseBox, cfg, ...
Expand All @@ -140,7 +140,7 @@
end

% End of the run for the BOLD to go down
WaitSecs(cfg.timing.endDelay);
waitFor(cfg, cfg.timing.endDelay);

cfg = getExperimentEnd(cfg);

Expand Down
58 changes: 35 additions & 23 deletions initEnv.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
% - struct
% - statistics
%
% MATLAB > R2017a
% MATLAB >= R2015b
%
% 2 - Add project to the O/M path

Expand All @@ -17,34 +17,28 @@
octaveVersion = '4.0.3';
matlabVersion = '8.6.0';

installlist = {'io', 'statistics', 'image'};

if isOctave

% Exit if min version is not satisfied
if ~compare_versions(OCTAVE_VERSION, octaveVersion, '>=')
error('Minimum required Octave version: %s', octaveVersion);
end

installlist = {'statistics', 'image'};
for ii = 1:length(installlist)

packageName = installlist{ii};

try
% Try loading Octave packages
disp(['loading ' installlist{ii}]);
pkg('load', installlist{ii});
disp(['loading ' packageName]);
pkg('load', packageName);

catch
errorcount = 1;
while errorcount % Attempt twice in case installation fails
try
pkg('install', '-forge', installlist{ii});
pkg('load', installlist{ii});
errorcount = 0;
catch err
errorcount = errorcount + 1;
if errorcount > 2
error(err.message);
end
end
end

tryInstallFromForge(packageName);

end
end

Expand All @@ -58,7 +52,9 @@

% If external dir is empty throw an exception
% and ask user to update submodules.
if numel(dir('lib')) <= 2 % Means that the external is empty
libDirectory = fullfile(fileparts(mfilename('fullpath')), 'lib');

if numel(dir(libDirectory)) <= 2 % Means that the external is empty
error(['Git submodules are not cloned!', ...
'Try this in your terminal:', ...
' git submodule update --recursive ']);
Expand All @@ -70,25 +66,41 @@

end

%%
%% Return: true if the environment is Octave.
%%
function retval = isOctave
% Return: true if the environment is Octave.
persistent cacheval % speeds up repeated calls

if isempty (cacheval)
cacheval = (exist ('OCTAVE_VERSION', 'builtin') > 0);
end

retval = cacheval;

end

function tryInstallFromForge(packageName)

errorcount = 1;
while errorcount % Attempt twice in case installation fails
try
pkg('install', '-forge', packageName);
pkg('load', packageName);
errorcount = 0;
catch err
errorcount = errorcount + 1;
if errorcount > 2
error(err.message);
end
end
end

end

function addDependencies()

pth = fileparts(mfilename('fullpath'));
addpath(genpath(fullfile(pth, 'lib', 'CPP_BIDS', 'src')));
addpath(fullfile(pth, 'lib', 'CPP_PTB'));
addpath(genpath(fullfile(pth, 'lib', 'CPP_PTB', 'src')));
addpath(fullfile(pth, 'subfun'));
addpath(fullfile(pth, 'input'));

end
2 changes: 1 addition & 1 deletion lib/CPP_BIDS
Submodule CPP_BIDS updated 50 files
+3 −0 .gitignore
+22 −17 .travis.yml
+57 −373 README.md
+3 −0 binder/apt.txt
+2 −0 binder/environment.yml
+3 −0 binder/postBuild
+144 −0 docs/functions_description.md
+97 −0 docs/installation.md
+223 −201 lib/utils/file_utils.m
+11 −0 manualTests/dummyData/.bidsignore
+9 −2 manualTests/miss_hit.cfg
+0 −0 manualTests/test_createDatasetDescription.m
+3 −3 manualTests/test_createJson.m
+139 −22 manualTests/test_makeRawDataset.m
+0 −41 manualTests/test_userInput.m
+8 −1 miss_hit.cfg
+11 −0 notebooks/README.md
+795 −0 notebooks/basic_usage.ipynb
+646 −0 notebooks/creating_BIDS_dataset.ipynb
+288 −0 notebooks/more_on_saving.ipynb
+67 −12 src/checkCFG.m
+4 −1 src/convertSourceToRaw.m
+0 −37 src/createBoldJson.m
+26 −22 src/createFilename.m
+127 −0 src/createJson.m
+28 −16 src/saveEventsFile.m
+19 −0 src/subfun/askForGroupAndOrSession.m
+33 −0 src/subfun/askUserCli.m
+42 −0 src/subfun/askUserGui.m
+34 −0 src/subfun/createQuestionList.m
+10 −0 src/subfun/getIsQuestionToAsk.m
+14 −0 src/subfun/isPositiveInteger.m
+0 −45 src/subfun/parseFunc.m
+52 −0 src/subfun/removeAllDateSuffix.m
+1 −0 src/subfun/returnHeaderName.m
+25 −0 src/subfun/setDefaultResponses.m
+11 −0 src/subfun/transferInfoToBids.m
+14 −57 src/userInputs.m
+8 −1 tests/miss_hit.cfg
+52 −0 tests/test_askForGroupAndOrSession.m
+35 −9 tests/test_checkCFG.m
+0 −41 tests/test_createBoldJson.m
+173 −56 tests/test_createFilename.m
+140 −0 tests/test_createJson.m
+24 −0 tests/test_createQuestionList.m
+29 −0 tests/test_getIsQuestionToAsk.m
+17 −0 tests/test_isPositiveInteger.m
+185 −61 tests/test_saveEventsFileSave.m
+32 −0 tests/test_setDefaultResponses.m
+9 −0 tests/test_transferInfoToBids.m
33 changes: 27 additions & 6 deletions setParameters.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,17 @@

% MRI settings
cfg = setMRI(cfg);

cfg.pacedByTriggers.do = true;

%% Experiment Design

% cfg.design.motionType = 'translation';
% cfg.design.motionType = 'radial';
cfg.design.motionType = 'translation';
cfg.design.names = {'static'; 'motion'};
cfg.design.possibleDirections = [-1 1]; % 1 motion , -1 static %NOT IN USE AT THE MOMENT
% cfg.design.nbBlocks = size(cfg.design.names, 2); % TO CHECK
cfg.design.nbRepetitions = 14; % AT THE MOMENT IT IS NOT SET IN THE MAIN SCRIPT
cfg.design.motionDirections = [-1 -1 1 1];
cfg.design.nbRepetitions = 14;
cfg.design.nbEventsPerBlock = 12;

%% Timing
Expand All @@ -51,15 +52,35 @@
% IBI
% block length = (cfg.eventDuration + cfg.ISI) * cfg.design.nbEventsPerBlock

cfg.timing.eventDuration = 0.850; % second

% Time between blocs in secs
cfg.timing.IBI = 1.8; % 8;
cfg.timing.IBI = 1.8;
% Time between events in secs
cfg.timing.ISI = 0;
% Number of seconds before the motion stimuli are presented
cfg.timing.onsetDelay = .1;
cfg.timing.onsetDelay = 0;
% Number of seconds after the end all the stimuli before ending the run
cfg.timing.endDelay = 3.6;

% reexpress those in terms of repetition time
if cfg.pacedByTriggers.do

cfg.pacedByTriggers.quietMode = true;
cfg.pacedByTriggers.nbTriggers = 1;

cfg.timing.eventDuration = cfg.mri.repetitionTime / 2 - 0.04; % second

% Time between blocs in secs
cfg.timing.IBI = 1;
% Time between events in secs
cfg.timing.ISI = 0;
% Number of seconds before the motion stimuli are presented
cfg.timing.onsetDelay = 0;
% Number of seconds after the end all the stimuli before ending the run
cfg.timing.endDelay = 2;
end

%% Auditory Stimulation

cfg.audio.channels = 2;
Expand All @@ -80,7 +101,7 @@
cfg.fixation.xDisplacement = 0;
cfg.fixation.yDisplacement = 0;

cfg.target.maxNbPerBlock = 0;
cfg.target.maxNbPerBlock = 2;
cfg.target.duration = 0.5; % In secs

cfg.extraColumns = {'direction', 'speed', 'target', 'event', 'block', 'keyName'};
Expand Down
48 changes: 18 additions & 30 deletions subfun/doAudMot.m → subfun/doAuditoryMotion.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [onset, duration] = doAudMot(cfg, thisEvent)
function [onset, duration] = doAuditoryMotion(cfg, thisEvent)

% Play the auditopry stimulation of moving in 4 directions or static noise bursts
%
Expand All @@ -11,48 +11,36 @@
% - thisEvent: structure that the parameters regarding the event to present
%
% Output:
% -
% - onset in machine time
% - duration in seconds
%

%% Get parameters

sound = [];

direction = thisEvent.direction(1);
isTarget = thisEvent.target(1);
targetDuration = cfg.target.duration;

soundData = cfg.soundData;

% if isTarget == 0
switch direction
case -1
fieldName = 'S';
case 90
fieldName = 'U';
case 270
fieldName = 'D';
case 0
fieldName = 'R';
case 180
fieldName = 'L';
end

if direction == -1
sound = soundData.S;
elseif direction == 90
sound = soundData.U;
elseif direction == 270
sound = soundData.D;
elseif direction == 0
sound = soundData.R;
elseif direction == 180
sound = soundData.L;
if isTarget == 1
fieldName = [fieldName '_T'];
end

% elseif isTarget == 1
%
% if direction == -1
% sound = soundData.S_T;
% elseif direction == 90
% sound = soundData.U_T;
% elseif direction == 270
% sound = soundData.D_T;
% elseif direction == 0
% sound = soundData.R_T;
% elseif direction == 180
% sound = soundData.L_T;
% end
%
% end
sound = soundData.(fieldName);

% Start the sound presentation
PsychPortAudio('FillBuffer', cfg.audio.pahandle, sound);
Expand Down
Loading