Skip to content

Commit 4109c3b

Browse files
committed
add devSandbox to develop PTB stimulation
1 parent fa8661c commit 4109c3b

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed

devSandbox.m

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
function devSandbox
2+
3+
cfg = struct;
4+
5+
cfg.backgroundColor = [ 127 127 127 ];
6+
7+
cfg = devSandbox_initPTB(cfg);
8+
9+
10+
% -------------------------------------------------------------------------
11+
% -------------------------- SET YOUR VARS HERE ---------------------------
12+
% -------------------------------------------------------------------------
13+
14+
% Define black and white
15+
white = WhiteIndex(cfg.screenNumber);
16+
black = BlackIndex(cfg.screenNumber);
17+
grey = white / 2;
18+
inc = white - grey;
19+
20+
% Grating size in pixels
21+
gratingSizePix = 600;
22+
23+
% Grating frequency in cycles / pixel
24+
freqCyclesPerPix = 0.01;
25+
26+
% Drift speed cycles per second
27+
cyclesPerSecond = 1;
28+
29+
% Contrast for our contrast modulation mask: 0 = mask has no effect, 1 = mask
30+
% will at its strongest part be completely opaque frameCounter.e. 0 and 100% contrast
31+
% respectively
32+
contrast = 0.8;
33+
34+
% We set PTB to wait one frame before re-drawing
35+
waitframes = 1;
36+
37+
% -------------------------------------------------------------------------
38+
39+
try
40+
41+
% -------------------------------------------------------------------------
42+
% ------------------------------ PLAYGROUND -------------------------------
43+
% -------------------------------------------------------------------------
44+
% Define Half-Size of the grating image.
45+
texsize = gratingSizePix / 2;
46+
47+
% First we compute pixels per cycle rounded to the nearest pixel
48+
pixPerCycle = ceil(1 / freqCyclesPerPix);
49+
50+
% Frequency in Radians
51+
freqRad = freqCyclesPerPix * 2 * pi;
52+
53+
% This is the visible size of the grating
54+
visibleSize = 2 * texsize + 1;
55+
56+
% Define our grating. Note it is only 1 pixel high. PTB will make it a full
57+
% grating upon drawing
58+
x = meshgrid(-texsize:texsize + pixPerCycle, 1);
59+
grating = grey * cos(freqRad*x) + inc;
60+
61+
% Make a two layer mask filled with the background colour
62+
mask = ones(1, numel(x), 2) * grey;
63+
64+
% Place the grating in the 'alpha' channel of the mask
65+
mask(:, :, 2)= grating .* contrast;
66+
67+
% Make our grating mask texture
68+
gratingMaskTex = Screen('MakeTexture', cfg.window, mask);
69+
70+
% Make a black and white noise mask half the size of our grating. This will
71+
% be scaled upon drawing to make a "chunky" noise texture which our grating
72+
% will mask. Note the round function in here. For this demo we are simply
73+
% rounding the size to the nearest pixel, leaving PTB to do some scaling.
74+
noise = rand(round(visibleSize / 2)) .* white;
75+
76+
% Make our noise texture
77+
noiseTex = Screen('MakeTexture', cfg.window, noise);
78+
79+
% Make a destination rectangle for our textures and center this on the
80+
% screen
81+
dstRect = [0 0 visibleSize visibleSize];
82+
dstRect = CenterRect(dstRect, cfg.windowRect);
83+
84+
% Calculate the wait duration
85+
waitDuration = waitframes * cfg.ifi;
86+
87+
% Recompute pixPerCycle, this time without the ceil() operation from above.
88+
% Otherwise we will get wrong drift speed due to rounding errors
89+
pixPerCycle = 1 / freqCyclesPerPix;
90+
91+
% Translate requested speed of the grating (in cycles per second) into
92+
% a shift value in "pixels per frame"
93+
shiftPerFrame = cyclesPerSecond * pixPerCycle * waitDuration;
94+
95+
% Sync us to the vertical retrace
96+
vbl = Screen('Flip', cfg.window);
97+
98+
% Set the frame counter to zero, we need this to 'drift' our grating
99+
frameCounter = 0;
100+
101+
% Loop until a key is pressed
102+
while ~KbCheck
103+
104+
% Calculate the xoffset for our window through which to sample our
105+
% grating
106+
xoffset = mod(frameCounter * shiftPerFrame, pixPerCycle);
107+
108+
% Now increment the frame counter for the next loop
109+
frameCounter = frameCounter + 1;
110+
111+
% Define our source rectangle for grating sampling
112+
srcRect = [xoffset 0 xoffset + visibleSize visibleSize];
113+
114+
% Draw noise texture to the screen
115+
Screen('DrawTexture', cfg.window, noiseTex, [], dstRect, []);
116+
117+
% Draw grating mask
118+
Screen('DrawTexture', cfg.window, gratingMaskTex, srcRect, dstRect, []);
119+
120+
% Flip to the screen on the next vertical retrace
121+
vbl = Screen('Flip', cfg.window, vbl + (waitframes - 0.5) * cfg.ifi);
122+
123+
end
124+
125+
126+
127+
% -------------------------------------------------------------------------
128+
129+
130+
devSandbox_cleanUp
131+
132+
catch
133+
134+
devSandbox_cleanUp
135+
psychrethrow(psychlasterror);
136+
137+
end
138+
139+
140+
end
141+
142+
143+
function cfg = devSandbox_initPTB(cfg)
144+
145+
Screen('Preference', 'SkipSyncTests', 2);
146+
147+
PsychDebugWindowConfiguration
148+
149+
% Here we call some default settings for setting up Psychtoolbox
150+
PsychDefaultSetup(2);
151+
152+
% Get the screen numbers
153+
cfg.screens = Screen('Screens');
154+
155+
% Draw to the external screen if avaliable
156+
cfg.screenNumber = max(cfg.screens);
157+
158+
% Open an on screen window
159+
[cfg.window, cfg.windowRect] = PsychImaging('OpenWindow', cfg.screenNumber, cfg.backgroundColor);
160+
161+
% Get the size of the on screen window
162+
[cfg.screenXpixels, cfg.screenYpixels] = Screen('WindowSize', cfg.window);
163+
164+
% Query the frame duration
165+
cfg.ifi = Screen('GetFlipInterval', cfg.window);
166+
167+
% Get the centre coordinate of the window
168+
[cfg.xCenter, cfg.yCenter] = RectCenter(cfg.windowRect);
169+
170+
% Set up alpha-blending for smooth (anti-aliased) lines
171+
Screen('BlendFunction', cfg.window, 'GL_SRC_ALPHA', 'GL_ONE_MINUS_SRC_ALPHA');
172+
173+
end
174+
175+
function devSandbox_cleanUp
176+
177+
% A wrapper function to close all windows, ports, show mouse cursor, close keyboard queues
178+
% and give access back to the keyboards.
179+
180+
WaitSecs(0.5);
181+
182+
Priority(0);
183+
184+
ListenChar(0);
185+
KbQueueRelease();
186+
187+
ShowCursor
188+
189+
% Screen Close All
190+
sca;
191+
192+
% Close Psychportaudio if open
193+
if PsychPortAudio('GetOpenDeviceCount') ~= 0
194+
PsychPortAudio('Close');
195+
end
196+
197+
if ~ismac
198+
% remove PsychDebugWindowConfiguration
199+
clear Screen
200+
end
201+
202+
close all
203+
204+
205+
end

0 commit comments

Comments
 (0)