https://github.com/chrischen2/eLife2020Stimulus.git
Raw File
Tip revision: dd7cc7b01d0fd41d62335ceef0f72a5e921cf374 authored by chrischen2 on 23 November 2020, 01:01:14 UTC
Add files via upload
Tip revision: dd7cc7b
checkerBar.m
function TwoDirsSerialCheckerBar(varargin)
oldLevel = Screen('Preference', 'Verbosity', 2);
portaddress = 49232;
config_io;
outp(portaddress,0);%initiate port value to 0
% seed 0, 1, 2, 3 is used respectively 
try
    %assign default values
    speed=400;   % pixels/s, roughly 440 um/s, rig dependent
    checker.freq=15;
    checker.size=40;
    prefD=315;
    numReps=3;
    numDirs=2;
    barWidth=100;
    barLength=400;
    movingRadius=300;
    barColor=50;  % new rig
    preStimWait=3;
    baseWait=1;
    switch speed
        case 1200
            interTrialWait=2;
        case 400
            interTrialWait=1;
        case 100
            interTrialWait=2.5;
            numReps=2;
            baseWait=0;
    end
    
    saveStimulus=1;
    screenColor = 0.01;
    dendrites=[0 0];  % dendrites=[ distnance_from_soma angle from_soma], use this to apply stimulus in remote dendritic branches
    checker.colors=[ 0 0.1 ];  % pixel intensity, see gamma chart for intensity 
    checker.colors=checker.colors(randperm(length(checker.colors)));
    
    interSerialWait=2;
    pvpmod(varargin) %assign valueTa
    maskRadius=movingRadius;
    Screen('Preference','VisualDebugLevel',2);
    Beep = MakeBeep(1000,0.1);
    lptwrite(portaddress, 0); %initialize parallel port to 0's, portaddress is the "base address" of our parallel port
    %generate direction list
    dirs =0:(360/numDirs):(360-(360/numDirs));
    directions = [];
    for r=1:numReps*length(checker.colors)
        dirs_shuffled = Shuffle(dirs);
        directions=cat(2,directions,dirs_shuffled);
    end
    directions=mod(directions+prefD,360)
    %generate matrix for stimulus file
    StimulusInfo=ones(length(directions),10+length(checker.colors));
    StimulusInfo(:,1)=directions;
    StimulusInfo(:,2)=StimulusInfo(:,2)*speed;
    StimulusInfo(:,3)=StimulusInfo(:,3)*barLength;
    StimulusInfo(:,4)=StimulusInfo(:,4)*barWidth;
    StimulusInfo(:,5)=StimulusInfo(:,5)*movingRadius;
    StimulusInfo(:,6)=StimulusInfo(:,6)*barColor;
    StimulusInfo(:,7)=StimulusInfo(:,7)*checker.size;
    StimulusInfo(:,8)=StimulusInfo(:,8)*checker.freq;
    StimulusInfo(:,9)=StimulusInfo(:,9)*dendrites(1);
    StimulusInfo(:,10)=StimulusInfo(:,10)*dendrites(2);
    for i=1:length(checker.colors)
        StimulusInfo(:,10+i)=StimulusInfo(:,10+i)*checker.colors(i);
    end
    if saveStimulus
        [dirFile,dirPath] = uiputfile('*.txt','Save directions as');
        fn=[dirPath dirFile];
        if isstr(fn)
            fid = fopen(fn, 'wt');
            fprintf(fid, '%6.2f %6.2f %6.2f %6.2f %6.2f    %6.2f %6.2f %6.2f %6.2f %6.2f   %6.2f %6.2f %6.2f  \n', StimulusInfo');
            fclose(fid);
        end
    end
    
    fprintf('%s %f seconds\n', 'set normal recording length to',...
        (2*movingRadius+barLength)/speed+1+interTrialWait);
    disp('press any key to continue...')
    pause;
    
    HideCursor
    %initialize screen
    AssertOpenGL;
    table=getGammaTable(0); %  %load most recent gamma table
    Screen('Preference', 'SkipSyncTests',0);
    screens=Screen('Screens');
    screenNumber=max(screens);
    %Open a fullscreen window
    [window,~]=Screen('OpenWindow',screenNumber, 0 , [], 32, 2);
    Screen('LoadNormalizedGammaTable', window, table); %use gamma corrected table
    %Enable Alpha blending % THis is a linear super-position
    Screen('BlendFunction', window, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    %Screen('BlendFunction', window, GL_SRC_ALPHA, GL_ONE);
    frameRate=1/Screen('GetFlipInterval',window);
    checker.nframe=ceil(frameRate/checker.freq); 
    priorityLevel=MaxPriority(window);
    Priority(priorityLevel);
    
    
    preStimFrame=floor(preStimWait*frameRate/checker.nframe)*checker.nframe;
    [x,y] = RectCenter(screenRect);
    cdstRect = [0 0 2*movingRadius 2*movingRadius];
    cdstRect=CenterRect(cdstRect, screenRect);
    cdstRect=CenterRectOnPoint(cdstRect,x+dendrites(1)*cosd(dendrites(2)),y+dendrites(1)*sind(dendrites(2)));
    
    ncheckers=floor(2*movingRadius/checker.size);  % spatial component
    padding = 1; % Region around bar drawn in texture matrix to be set to zero alpha
    %make texture with transparent border for smoother motion
    barTex = ones(barWidth, barLength+(2*padding), 2)*barColor;
    barTex(:,:,2) = 0;
    barTex(1:barWidth, 1+padding:barLength+padding, 2) = 255;
    tex = Screen('MakeTexture', window, barTex);
    for c=1:length(checker.colors)
        if KbCheck
            break; % Exit loop
        end
        dlist=directions( (c-1)*numReps*num_dirs+1:c*num_dirs*numReps);
        checker.color=checker.colors(c);
        [checkerboard] = makeRandchecker( checker.color,checker.size,ncheckers,maskRadius,0, ...,
            ceil((preStimFrame+60)/checker.nframe));
        checkerTexture = Screen('MakeTexture', window, squeeze(checkerboard(:,:,1)));
        % checkerboard is 3D, create additonal 60 frames just in case
        for i=1:preStimFrame
            Screen('DrawTextures', window, checkerTexture,  [],cdstRect, 0, 0);
            Screen('Flip', window);
            cpat=squeeze(checkerboard(:,:,ceil(i/checker.nframe)));
            checkerTexture = Screen('MakeTexture', window, cpat);
        end
        
        Snd('Play',Beep);
        
        
        for trial=1:length(dlist)
            direction=dlist(trial);
            showMovingBar(window,screenRect,tex,frameRate,checker,cdstRect,'interTrialWait',interTrialWait,...
                'frameRate',frameRate, 'direction',direction,'barWidth',barWidth,'baseWait',baseWait,...
                'barLength',barLength,'barColor',barColor,...
                'speed',speed,'movingRadius',movingRadius,'screenColor',screenColor,'maskRadius',maskRadius,'dendrites',dendrites);
        end
        Screen('FillOval',window,0,screenRect);
        Screen('Flip',window);
        WaitSecs(interSerialWait);
    end
    Snd('Play',Beep);
    sca;
    Screen('Preference','Verbosity', oldLevel);
    Priority(0);
    KbWait;
catch
    Snd('Play',Beep);
    KbWait;
    ShowCursor
    sca;
    Screen('Preference','Verbosity', oldLevel);
    Priority(0);
    rethrow(lasterror);
end
return


function []=showMovingBar(window,screenRect,tex,frame_rate,checker,cdstRect,varargin)
pvpmod(varargin) %assign values
[x,y] = RectCenter(screenRect);
endRadius = -movingRadius-barLength;
ncheckers=floor(2*movingRadius/checker.size);


[mask,sz]=makeCircularMask(maskRadius,'bg',0);
masktex=Screen('MakeTexture', window, mask);
maskRect=[0 0 sz sz];
maskRect=CenterRect(maskRect, screenRect);
maskRect=CenterRectOnPoint(maskRect,x+dendrites(1)*cosd(dendrites(2)),y+dendrites(1)*sind(dendrites(2)));

%output trigger pulse
portaddress = 49232;
config_io;
outp(portaddress,0);%initiate port value to 0

%output trigger pulse
outp(portaddress, 255);%3020 is the "base address" of our parallel port
WaitSecs(.0005);
outp(portaddress, 0);
WaitSecs(.1);

baseFrame=ceil(baseWait*frameRate/checker.nframe)*checker.nframe+checker.nframe;
[checkerboard] = makeRandchecker( checker.color,checker.size,ncheckers,maskRadius,1, ...,
    ceil((baseFrame+60)/checker.nframe));
checkerTexture = Screen('MakeTexture', window, squeeze(checkerboard(:,:,1)));
% checkerboard is 3D, create additonal 60 frames just in case
for i=1:base_frame
    Screen('DrawTextures', window, checkerTexture,  [],cdstRect, 0, 0);
    Screen('Flip', window);
    cpat=squeeze(checkerboard(:,:,ceil(i/checker.nframe)));
    checkerTexture = Screen('MakeTexture', window, cpat);
end

barTime= (2*movingRadius+barLength)/speed;
barFrame=ceil(barTime*frame_rate/checker.nframe)*checker.nframe;
count=0;
[checkerboard] = makeRandchecker( checker.color,checker.size,ncheckers,maskRadius,2, ...,
    ceil((barFrame+60)/checker.nframe));
while movingRadius >= endRadius
    % Make the checkerboard into a texure (4 x 4 pixels)
    %         Screen('FillRect', window,screen_color, []);
    startPos = [x+((movingRadius+barLength/2)*cosd(direction))+dendrites(1)*cosd(dendrites(2))...
        y+((movingRadius+barLength/2)*sind(direction))+dendrites(1)*sind(dendrites(2))];% startPosition [x y]
    dstRect = [0 0 barLength+2 barWidth];
    dstRect = CenterRectOnPoint(dstRect, startPos(1), startPos(2));
    
    %         Screen('DrawTexture', window, masktex, [],maskRect,0);
    Screen('DrawTexture',window,tex,[],dstRect,direction,0);
    Screen('DrawTexture', window, masktex, [],maskRect,0);
    Screen('Flip', window);

    movingRadius = movingRadius-(speed/frameRate);
    
    count=count+1;
    if KbCheck
        return; % Exit loop
    end
    Screen('DrawTextures', window, checkerTexture,  [],cdstRect, 0, 0);
    Screen('Flip', window);
    cpat=squeeze(checkerboard(:,:,ceil(count/checker.nframe)));
    checkerTexture = Screen('MakeTexture', window, cpat);
end

waitFrame=ceil(interTrialWait*frameFate/checker.nframe)*checker.nframe;
[checkerboard] = makeRandchecker( checker.color,checker.size,ncheckers,maskRadius,3, ...,
    ceil((waitFrame+60)/checker.nframe));
for i=1:waitFrame
    Screen('DrawTextures', window, checkerTexture,  [],cdstRect, 0, 0);
    Screen('Flip', window);
    cpat=squeeze(checkerboard(:,:,ceil(i/checker.nframe)));
    checkerTexture = Screen('MakeTexture', window, cpat);
end
function [mask,sz]=makeCircularMask(maskRadius,varargin)

interior_val=0;
exterior_val=255;
bg=0.5;
diat=2;
sz=1000;
pvpmod(varargin)
mask=ones(sz/diat, sz/diat, 2) * bg;
center = [floor(sz/(diat*2)) floor(sz/(diat*2))];
for r=1:sz/diat
    for c=1:sz/diat
        if sqrt((r-center(1))^2+(c-center(2))^2)<=maskRadius/diat
            mask(r,c,2)=interior_val;
        else
            mask(r,c,2)=exterior_val;
        end
        
    end
end

return





back to top