
function DriftGratings_Sounds_main
clearvars -global -except Ard TL ftl; clearvars; sca;
% clear all; clear global; clear mex; sca; %#ok<CLMEX,CLALL>
[scriptPath, scriptName] = fileparts(mfilename('fullpath')); %#ok<*ASGLU>
TimeAnimation=0; stim_id_list=[]; 
Screen('Preference', 'SkipSyncTests', 1); %to skip synchronization failure set to 1

Param. Dichoptic = 0; Param.stereoMode = 0; %1
Param.SphericalCorrection = 0;
Param. screenid  = 2 ; % it matters only if Param.Dichoptic=0;
monitor_dist_cm  = 7;%14;%13;
monitor_size_horiz_cm = 22; % Acer (3D) GN246HL is 53. Projector is 25.
monitor_size_vert_cm  = 14; % used for CurvCorrection. Acer (3D) GN246HL is 30.
% Set random or sequential sequence of stimuli (directions or positions):
% Param.seqmode='random'; %'sequential'
Param.seqmode='sequential';
Param.fullyInterleaved = 1 ; %
Param.prestimInterval  = 2 ; %sec
Param.usePhotodiode = 0;
Param.useDAQdevice  = 0;
Param.useArduino    = 1;
Param.triggerAcquisition = 1; % send TTL signal to acquisition software to start/stop recording
test = 0 ;          % set to 1 if you want to test the stimulation without external triggering
test_screen = 0 ;   % set to 1 if you want to test the stimulation on a smaller screen; 0=full field.
loadMyGammaTable = 0 ;

    frame_rate   = 30.95; %Hz
    calc_frames  =  0;
                            
    Param.StimProtocols.  DriftingGrating        = 2; % set to 2 for "navigation stim"
    Param.StimProtocols.  DriftingGratingSound   = 0 ;
%     Param.StimProtocols.  DriftingGratingSoundLR = 0 ;
    
%% DG
reps       = 4;
stim          = 3; %sec, stimulus duration
poststim_time = 1.5; %sec, post-stimulus duration
tf         = [2]; %Hz
sf         = [0.05]; %cpd
angles     = [0 135 270 90 225 315 45 180];%[0 90 180 270];
if Param.StimProtocols.DriftingGrating
    global DG %#ok<*TLEV>
	DG.n_reps = reps(1) ; % number of repetitions (1 repetition = each direction once).
	DG.drawMask = 0; % draw grating through circular aperture
	DG.maskCenter_offset = [+0/10, 0/6]; %set the aperture center (rightward, downward from screen center, values in % of screen):
	DG.maskSize_deg = 70; %deg
	DG.spacfreq = sf(1); %cpd  
	DG.cyclespersecond = tf(1) ;
	DG.directions = numel(angles); % Set the number of directions you want to be presented:
    DG.angles = angles;%[]; % specify cartesian angles
    DG.offset_rot_deg = [  0  ] ; %#ok<*NBRAK>
	DG.stimulus_time = stim(1) ; % seconds per stimulus direction
	DG.poststim_time = poststim_time ; % seconds per blank stimulus (gray screen that precedes the stimulus)
	DG.sinwave = 1;        % 1 = sine wave grating, 0 = square grating
    DG.phase = []; % initial phase
    DG.amplitude = 0.35; % contrast (if 0.5->100%)
    DG.BackgroundLuminance = 127;
    DG.stim_id = 1;  stim_id_list=[stim_id_list;DG.stim_id];   % for the 'putsample' value
    if Param.StimProtocols.DriftingGrating==2
        DG.n_reps = 300 ;
        DG.drawMask = 0;
        DG.spacfreq = 0.04; %cpd  
        DG.cyclespersecond = 2 ;
        DG.directions = 12; DG.angles = [];
        DG.stimulus_time = 2 ;
        DG.poststim_time = 3 ;
        Param.prestimInterval  = 1 ; %sec
        set_stimProtocols_toZero
    end
    DG.time = DG.n_reps*DG.directions*(DG.poststim_time+DG.stimulus_time);
    TimeAnimation = TimeAnimation + DG.time;
end

if Param.StimProtocols.DriftingGratingSound
    global DG2 %#ok<*TLEV>
    audio_file = 'C:\Users\imaging\Documents\MATLAB\2019-08-01 stim\tone1.mat'; %#ok<NASGU>
	DG2.n_reps = reps(1) ; % number of repetitions (1 repetition = each direction once).
	DG2.drawMask = 0; % draw grating through circular aperture
	DG2.maskCenter_offset = [+0/10, 0/6]; %set the aperture center (rightward, downward from screen center, values in % of screen):
	DG2.maskSize_deg = 70; %deg
	DG2.spacfreq = sf(1); %cpd  
	DG2.cyclespersecond = tf(1) ;
	DG2.directions = numel(angles); % Set the number of directions you want to be presented:
    DG2.angles = angles;%[]; % specify cartesian angles
    DG2.offset_rot_deg = [  0  ] ; %#ok<*NBRAK>
	DG2.stimulus_time = stim(1) ; % seconds per stimulus direction
	DG2.poststim_time = poststim_time ; % seconds per blank stimulus (gray screen that precedes the stimulus)
	DG2.sinwave = 1;        % 1 = sine wave grating, 0 = square grating
    DG2.phase = []; % initial phase
    DG2.amplitude = 0.35; % contrast (if 0.5->100%)
    DG2.BackgroundLuminance = 127;
    DG2.stim_id = 2;  stim_id_list=[stim_id_list;DG2.stim_id];   % for the 'putsample' value
    DG2.time = DG2.n_reps*DG2.directions*(DG2.poststim_time+DG2.stimulus_time);
    TimeAnimation = TimeAnimation + DG2.time;
end
%% Set screen parameters, saving folder
try
% Choose screen:
% screenid = max(Screen('Screens'));
numScreens = Screen('Screens');
        mouse_dist_cm = monitor_dist_cm;%13%20%13.3%#ok<*NOPRT> %12.7%19 %18.8 ;
        screenSize_cm_horz = monitor_size_horiz_cm;%44;%47.5%44;
Param.mouse_dist_cm = mouse_dist_cm;
Param.screenSize_cm_horz = screenSize_cm_horz;
Param.screenSize_cm_vert = monitor_size_vert_cm;

TimeAnimation = TimeAnimation + Param.prestimInterval;
    frame_time = 1/frame_rate;
    framesTOT = ceil( TimeAnimation / frame_time );
    disp(['Total time for whole stimulation is ' num2str(TimeAnimation/60) ' min.'])
    disp(['Total number of frames with frame rate ' num2str(frame_rate,'%5.2f') ' Hz (frame time ' num2str(frame_time*1000,'%5.0f') ' ms) is:' ])
    disp([num2str(framesTOT) ' frames'])
    if calc_frames, return, end;
% Check if the stim_id of the stimuli are far enough:
thr_stimid=0;
if any(abs(diff(sort(stim_id_list))) <= thr_stimid )
    warndlg({['The stim_id used are too close, you won''t be able to distinguish the different stimuli! Aborting...'];...
             [ 'stim_id_list = ' mat2str(stim_id_list')]} )
    return
end

if     strfind(eval('computer'),'WIN')
    save_dir=['C:\Users\imaging\Documents\MATLAB\stim_data\' datestr(now, 'yyyy_mm_dd')];
elseif strfind(eval('computer'),'LNX')
    save_dir=['/home/alessandro/Dropbox/Code/alessandro/stim_data/' datestr(now, 'yyyy_mm_dd')];
end
if ~isdir(save_dir), mkdir(save_dir), end;
datetime_suffix = datestr(now, 'yyyy_mm_dd_HH_MM_SS') ;
global stim_fname
stim_fname = [save_dir filesep 'InfoStim-' datetime_suffix '-DriftGrating_RetPos_PhiMotion'];
Param.save_dir = save_dir; Param.datetime_suffix = datetime_suffix;
Param.stim_fname = stim_fname;

internalRotation = 1; % 1=rotation of the gratings inside the "box", 0=rotation of the box.
if   internalRotation, Param.rotateMode = kPsychUseTextureMatrixForRotation;
else                   Param.rotateMode = []; end;

    %% Open window and get basic screen parameters

% Open a fullscreen onscreen window on that display:

if     test_screen == 0

    
    Param = SetCurvatureCorrection( Param );

        [screen(1), Param.screenRect] = Screen('OpenWindow', Param.screenid(1), 200 );
    HideCursor(Param.screenid);
elseif test_screen == 1
    mon_pos = get(0,'MonitorPositions');
    pos_screen1 = [         50       50  round(mon_pos(1,3)*1/2)                  round(mon_pos(1,4)*2/3) ];
        [screen(1), Param.screenRect] = Screen('OpenWindow', Param.screenid(1), 127, pos_screen1 );
end
if loadMyGammaTable == 0
    LoadIdentityClut(screen);
end
% when stereoMode==4 or 1, Param.screenRect(3) is half the whole screen width
Param.screenRes = [Param.screenRect(3), Param.screenRect(4)];


% Make sure this is running on OpenGL Psychtoolbox:
AssertOpenGL;
% Make sure the GLSL shading language is supported:
AssertGLSL;
Priority(MaxPriority(screen));
% Retrieve video redraw interval for later control of our animation timing:
Param.ifi = Screen('GetFlipInterval', screen(1));
% Calculates the visual angle subtended by a single pixel:
    % see http://psychtoolbox.org/PTB-2/download/FineTutorial/revision_2/MatClassAll.rtf
Param.pixel_cm  = screenSize_cm_horz/Param.screenRect(3); % calculates the size of a pixel in cm
degperpix = (2*atan(Param.pixel_cm./(2*mouse_dist_cm(1)))).*(180/pi);  %%true only for small angles, more generally would be: atan(pix./animal_dist_cm)  %*(180/pi) is necessary because atan in matlab gives result in radians
Param.pixperdeg = 1./degperpix;


%% SetDAQdevice
try
    % If Param.useDAQdevice==1 set DAQ device for stim analog output and digital input from laser shutter:
    SetDAQdevice_64bit
catch ME
    warning('Error in SetDAQdevice_64bit')
	Screen('CloseAll');
    Priority(0);
	ShowCursor;
    % Bye bye!
    rethrow(ME)
    clearvars -global -except Ard TL ftl;
    clearvars;
    return;  
end

if Param.usePhotodiode
	Param.Photodiode = SetPhotodiode(Param.screenRect);
end

%% Set parameters of stimulations
Param.stimSeq = {};
if Param.StimProtocols.DriftingGrating
    [ DG, Param ] = SetDriftingGratings( screen(1), DG, Param )
end

if Param.StimProtocols.DriftingGratingSound
    [ DG2, Param ] = SetDriftingGratings( screen(1), DG2, Param )
    % Perform basic initialization of the sound driver:
    InitializePsychSound;
    device = [];
    nrchannels = 2;
    DG2.sound = load( audio_file );
    DG2.wavedata = [DG2.sound.y, DG2.sound.y]';
    DG2.pahandle = PsychPortAudio('Open', device, [], 0, DG2.sound.Fs, nrchannels);
    
%     DG2.soundplayer = audioplayer(DG2.sound.y, DG2.sound.Fs);
end
% make stimSeq a row numeric array:
Param.stimSeq = cat(2, Param.stimSeq{:} );
if Param.fullyInterleaved
	Param.stimSeq = Param.stimSeq(randperm(length(Param.stimSeq))); % elements 1 to 4 shuffled
end

Param.test=test;
Param.test_screen=test_screen;
Param.prestimInterval_fr=round(Param.prestimInterval/Param.ifi);
save(stim_fname, 'Param');

%% Present stimuli
prestimColor = 127;
    if Param.StimProtocols.DriftingGrating
        prestimColor = DG.BackgroundLuminance ;
    end
    if Param.StimProtocols.DriftingGratingSound
        prestimColor = DG2.BackgroundLuminance ;
    end
if     Param.stereoMode==0
    for i=1:length(screen)
        Screen('FillRect', screen(i), prestimColor);
        Screen('Flip', screen(i));
    end
end
% Wait trigger to start stimulation protocol:
if test == 1 || Param.useDAQdevice==0 % Wait for release of all keys on keyboard, then sync us to retrace:

    disp(' Waiting for starting input..... Press Ctrl to start!');
    while ~KbCheck
    end
    pause(0.5)
    
    if Param.triggerAcquisition == 1 % send TTL signal to acquisition software to start recording
        global Ard
        writeDigitalPin(Ard, Param.ArdPinNr_trig, 1); % set to 5V
    end
    
else  % Wait for trigger to start animation
    
    disp(' '); disp(' ');
    disp(' Waiting for trigger input.....');
    while inputSingleScan(nidaq)<0.5;
        Exit_If_Shift(test,nidaq,'only_shift')
    end
    
end
disp(' ');
disp([' ---> Animation started!  ( preStim interval ' num2str(Param.prestimInterval) 's)']);
pause(1); disp(' ');
% Initial prestim interval with grey screen
% just a flip to get the vbl:
vbl = Screen('Flip', screen(1));

tic_start=tic;
for i = 1:Param.prestimInterval_fr
    if     Param.stereoMode==0
        for i=1:length(screen)
            vbl = Screen('Flip', screen(i), vbl + 0.5 * Param.ifi);
        end
    else
        vbl = Screen('Flip', screen(1), vbl + 0.5 * Param.ifi);
    end
	Exit_If_Shift(test,nidaq)
end
% Animation loop: press 'shift' to exit
% (stim files are saved when you interrupt)
for s = 1:length(Param.stimSeq) % for all stimuli and reps
%     tic_stim=tic;
    if 	   exist('DG','var') && Param.stimSeq(s)==DG.stim_id % 
        [DG,  vbl] = PresentDriftingGrating( nidaq, screen, vbl, Param, DG );
		    DG.cnt = DG.cnt+1;
    elseif exist('DG2','var') && Param.stimSeq(s)==DG2.stim_id % 
        [DG2, vbl] = PresentDriftingGratingSound( nidaq, screen, vbl, Param, DG2 );
		    DG2.cnt = DG2.cnt+1;
    end
    if exist('scriptName','var') && s==1
        BackupStimulusScript( scriptPath, scriptName, save_dir )
    end
end

StimSignal( Param, test, nidaq, 0 )

if     Param.stereoMode==0
    for i=1:length(screen)
        Screen('FillRect', screen(i), 80);
        Screen('Flip', screen(i));
    end
end

%% Closes windows and save parameters:

SaveParameters_script;
disp(['* StimInfo file saved in ' save_dir ]);


Param.tempo_tot=toc(tic_start);
disp(['* Whole animation lasted ' num2str(Param.tempo_tot/60) ' min.' ]);
if test == 1 || Param.useDAQdevice==0 % Wait key press to close screen:
    while KbCheck == 0
    end
elseif  test == 0 && Param.useDAQdevice==1 % Wait shutter closure to close screen:
    while inputSingleScan(nidaq)>0.5
    end
end
LoadIdentityClut(screen);
Screen('CloseAll');
Priority(0);
ShowCursor;

catch
    Screen('CloseAll');
    Priority(0);
    ShowCursor;
    psychrethrow(psychlasterror);
end


end