function Dotty_Experiment_Final %cast as function for imporved speed. %% DAQ Variant of SingleDotty with XLSread from a filegui % %% daq variant of SingleDot commandwindow if 0 Screen('Preference', 'SkipSyncTests', 1); disp('BAD TIMING MODE!!') else Screen('Preference', 'SkipSyncTests', 0); disp('ATTEMPTING TO USE GOOD TIMING - S') end % Clear the workspace close all; clear all; sca; % STIMULUS AND RECOVERY str_filename = input('FILENAME TO SAVE FOR THIS EXPERIMENT? (zero padded to 3 digits) ','s'); [xls_file,xls_folder]=uigetfile('*.xl*'); load_xls =fullfile(xls_folder,xls_file); exp_data = xlsread(load_xls, 1, 'A2:G7'); audio_enabled_list = exp_data(:,1)'; % is METRONOME enabled? MIC is always enabled! moving_dot_enabled_list = exp_data(:,2)'; % else we have fixation cross. DIO_required_list = exp_data(:,3)'; LED_flashing_list = exp_data(:,5)'; apdm_sync_list = exp_data(:,4)'; pause_experiment = exp_data(:,6)'; tempo_order_list = exp_data(:,7)'; num_trials = length(audio_enabled_list); %% Here we call some default settings for setting up Psychtoolbox PsychDefaultSetup(2); % Get the screen numbers screens = Screen('Screens') % Draw to the external screen if avaliable screenNumber = max(screens); % Define black and white white = WhiteIndex(screenNumber); black = BlackIndex(screenNumber); % Open an on screen window [window, windowRect] = PsychImaging('OpenWindow', screenNumber, black); % Get the size of the on screen window [screenXpixels, screenYpixels] = Screen('WindowSize', window); % Query the frame duration ifi = Screen('GetFlipInterval', window); % Get the centre coordinate of the window [xCenter, yCenter] = RectCenter(windowRect); % Make an Oval of 200 by 200 pixels baseOval = [0 0 150 150]; % Set the color of the Oval to red OvalColor = white; %[1 0 0]; %% variant slow to fast also defined in the XLS % Maximum priority level topPriorityLevel = MaxPriority(window); Priority(topPriorityLevel); for iterations = 1:num_trials if pause_experiment(iterations) [xCenter, yCenter] = RectCenter(windowRect); Screen('TextSize', window, 75); DrawFormattedText(window, ['WAIT 5s'], xCenter-(4*75), yCenter, [1 1 1]); % Flip to the screen Screen('Flip', window); pause(5) if pause_experiment(iterations)==2 % challenge and await response before ending pause [xCenter, yCenter] = RectCenter(windowRect); Screen('TextSize', window, 75); DrawFormattedText(window, ['PRESS ANY KEY'], xCenter-525, yCenter, [1 1 1]); % Flip to the screen Screen('Flip', window); KbWait; end else audio_enabled = audio_enabled_list(iterations); moving_dot_enabled = moving_dot_enabled_list(iterations); apdm_sync = apdm_sync_list(iterations); DIO_required = DIO_required_list(iterations); LED_flashing = LED_flashing_list(iterations); % this may go back into the loop? period_change_trial = ceil(rand * 9) + 6; initial_period_variation = ceil((rand * 95) + 5)/1000; second_period_variation = ceil((rand * 95) + 5)/1000; sav_filename = [str_filename num2str(iterations,'% 04.f')]; %% now we check for slow or fast TEMPO first... if tempo_order_list(iterations) period_second = (0.650 + initial_period_variation) * ones(period_change_trial,1); period_first = 0.870 + second_period_variation; periods = [period_second; period_first]; else period_first = (0.650 + initial_period_variation) * ones(period_change_trial,1); period_second = 0.870 + second_period_variation; periods = [period_first; period_second]; end period_shift_time = sum( periods(1:end-1)); max_time = 40; % Our Oval will oscilate with a sine wave function, up and down. % These are the parameters for the sine wave % See: http://en.wikipedia.org/wiki/Sine_wave amplitude = screenYpixels * 0.25; frequency = 1/ periods(1); angFreq = 2 * pi * frequency; startPhase = 0; time = 0; overall_time = 0; inputdata = []; if 1 % DAQ IS ALWAYS ENABLED - but not necessarily AUDITORY METRONOME try fclose('all'); delete('log.bin'); catch disp('no leftover logs') end fid1 = fopen('log.bin','w');%log_file for data - we can rename it later %% insert session based DAQ here. disp('SESSION BASED INTERFACE') dev = 'Dev2'; SampleRate = 1000; tone_duration = 50; % 100 milliseconds hard coded for tone and LEDs DAQ_time = 0:1/SampleRate:max_time; %SampleRate for max_time; data_expanded_first = amplitude * sin(angFreq * DAQ_time + startPhase); % this only does metronome one frequency_second = 1/ periods(end); angFreq_second = 2 * pi * frequency_second; data_expanded_second = amplitude * sin(angFreq_second * DAQ_time + startPhase); % this only does metronome one length_first = ceil((sum(periods(1:end-1)))* SampleRate) ;%ensures full period length_second = (max_time * SampleRate) - length_first;%ensures begins at 0 phase data_expanded = [data_expanded_first(1:length_first) data_expanded_second(1:length_second)]; [maxtab, mintab]=peakdet(data_expanded, 0.1); peaks = length(mintab); %% create an Arry of 0000's for data is we are metronome silent data = zeros(max_time * SampleRate,1); %else we actually make some audio! if audio_enabled for peak_iterations = 1: peaks peak_onset = mintab(peak_iterations,1); if (peak_onset + tone_duration) > (max_time * SampleRate) disp('MIN PEAK CLOSER THAN TONE DURATION TO END') data(peak_onset:end) = 1; else data(peak_onset:(peak_onset + tone_duration)) = 1; end end %% tone to mask amp=0.5; % VOLUME! fs=SampleRate ; % sampling frequency duration=max_time; freq=800; % Audio Freq. values=0:1/fs:duration; values = values(1:length(data)); audio_tone=amp*sin(2*pi* freq*values)'; %% then mask a nice sounding sine wave with the block data = data.*audio_tone; % Element wise multiplacation to make masked tone. %% * 5 boosts volume massively... if (audio_enabled && ~moving_dot_enabled) %% INSERT A FIXATION CROSS fixationFont = 150; [xCenter, yCenter] = RectCenter(windowRect); Screen('TextSize', window, fixationFont); DrawFormattedText(window, ['+'], xCenter-(fixationFont/2), yCenter-(fixationFont/2), [1 1 1]); % Flip to the screen Screen('Flip', window); end end %in_ch = [0 1]; % one for audio, one for audio_feedback %% SESSION AI in_ch = [3]; %AI0 and AI1 NI_channels =daq.createSession('ni'); ai_chan.InputType = 'SingleEnded'; ai_chan = addAnalogInputChannel(NI_channels,dev,in_ch,'Voltage'); %% AO + DIO ao_chans = [1]; %number of channels based on data matrix ao_chan = addAnalogOutputChannel(NI_channels,dev,ao_chans,'Voltage'); if DIO_required if apdm_sync % FOR SENDING SYNC TO APDM ET CETERA - or for LEDs? %% DIO - to add back in we need two more channels added to 'data' % starting with 0 and ending with 0 but 1 in the middle % NI_channels.queueOutputData(data) below adds data to all % available output channels (A and D) in one gesture.. timing % between the two is an unknown though when launched by % startForeground... %make 2 extra data channels for the DIO - %all 1s except last - otherwise it latches extra_DIO_data = ones(length(data),2); extra_DIO_data(end,1:2) = 0; data = [data extra_DIO_data]; dio_chan = addDigitalChannel(NI_channels,dev,'Port0/Line0:1','OutputOnly'); elseif LED_flashing extra_DIO_data = zeros(max_time * SampleRate,1); %by analogy to the tones for peak_iterations = 1: peaks peak_onset = mintab(peak_iterations,1); if (peak_onset + tone_duration) > (max_time * SampleRate) disp('MIN PEAK CLOSER THAN TONE DURATION TO END') data_extra_DIO(peak_onset:end) = 1; else data_extra_DIO(peak_onset:(peak_onset + tone_duration)) = 1; end end %% we may want to peak det the moving dot data for this % currently we just have them all all time....! extra_DIO_data([1,end]) = 0; %LEDS START AND END OFF data = [data extra_DIO_data extra_DIO_data]; dio_chan = addDigitalChannel(NI_channels,dev,'Port0/Line0:1','OutputOnly'); end end if (1) % prepend two frames of silent data % alternatively you can stall the visual metronome [r_data, c_data] = size(data); prepend_length = ceil( 2 *ifi * SampleRate); % we vbl on the blank referesh of the screen for the dots data_prepend = zeros( prepend_length, c_data); NI_channels.queueOutputData(data_prepend); end if (audio_enabled && ~moving_dot_enabled) DrawFormattedText(window, ['+'], xCenter-(fixationFont/2), yCenter-(fixationFont/2), [0 0 0]); % Flip to the screen Screen('Flip', window); end NI_channels.Rate=SampleRate; % %NI_channels.NumberOfScans = length(data); only works with AI solo NI_channels.queueOutputData(data); % this enforces AI and AO duration NI_channels.IsContinuous = true; lh = addlistener(NI_channels,'DataAvailable',@(src, event)logData(src, event, fid1)); % this speeds up the next call... allowing start to be more timely. %NI_channels prepare(NI_channels); startBackground(NI_channels); NI_release = GetSecs; % this takes 110ms end overall_time = 0; % Sync us and get a time stamp waitframes = 1; vbl = Screen('Flip', window, NI_release + (waitframes - 0.5) * ifi ); postflip_vbl = vbl - NI_release % Loop the animation until 40 seconds recover_ypos = []; recover_time = []; if moving_dot_enabled %else we have fixation cross. time_check = []; while overall_time= sum( periods(1:end-1)) % TRUE if (overall_time == time) if time >= (ceil(sum(periods(1:end-1)) / ifi))*ifi % hacked to reflect IFI frequency = 1/ periods(end); angFreq = 2 * pi * frequency; time = 0; % latch it back to end end end %blank out oval Screen('FillOval', window, [0 0 0], centeredRect); Screen('Flip', window); else %% INSERT A FIXATION CROSS fixationFont = 150; [xCenter, yCenter] = RectCenter(windowRect); Screen('TextSize', window, fixationFont); DrawFormattedText(window, ['+'], xCenter-(fixationFont/2), yCenter-(fixationFont/2), [1 1 1]); % Flip to the screen Screen('Flip', window); while overall_time