1
function PsychPortAudioTimingTest(exactstart, deviceid, latbias, waitframes, useDPixx)
2
% PsychPortAudioTimingTest([exactstart=1] [, deviceid=-1] [, latbias=0] [, waitframes=1] [,useDPixx=0])
1
function PsychPortAudioTimingTest(exactstart, deviceid, latbias, waitframes, useDPixx, triggerLevel)
2
% PsychPortAudioTimingTest([exactstart=1][, deviceid=-1][, latbias=0][, waitframes=1][, useDPixx=0][, triggerLevel=0.01])
4
4
% Test script for sound onset timing reliability and sound onset
5
5
% latency of the PsychPortAudio sound driver.
40
38
% audio onset time wrt. to visual stimulus onset.
41
39
% 0 -- Don't use DataPixx. This is the default.
41
% 'triggerLevel' = Sound signal amplitude for DataPixx to detect sound
42
% onset. Defaults to 0.01 = 1% of max amplitude if
43
% exactstart == 0, otherwise it is auto-detected by
44
% calibration. This will likely need tweaking on your
45
% setup. If the measured audio onset delta by DataPixx is
46
% much lower (or almost zero) than the expected delta
47
% reported by PsychPortAudio, then the triggerLevel may be
48
% too low and you should try if slightly higher thresholds
49
% help to discriminate signal from noise. Too high values
50
% may cause a hang of the script. In practice, levels
51
% between 0.01 and 0.1 should yield good results. Setting
52
% the 'useDPixx' flag to 2 also plots the waveforms
53
% captured by DataPixx, which may help in selection of the
54
% optimal triggerLevel.
44
57
% Initialize driver, request low-latency preinit:
45
58
InitializePsychSound(1);
113
126
suggestedLatencySecs = [];
116
suggestedLatencySecs = 0.015 %#ok<NOPRT>
129
% Hack to accomodate bad Windows systems or sound cards. By default,
130
% the more aggressive default setting of something like 5 msecs can
131
% cause sound artifacts on cheaper / less pro sound cards:
132
suggestedLatencySecs = 0.015 %#ok<NOPRT>
133
fprintf('Choosing a high suggestedLatencySecs setting of 15 msecs to account for shoddy Windows operating system.\n');
134
fprintf('For low-latency applications, you may want to tweak this to lower values if your system works better than average timing-wise.\n');
119
137
% Needs to determined via measurement once for each piece of audio
155
172
prelat = PsychPortAudio('LatencyBias', pahandle, latbias) %#ok<NOPRT,NASGU>
156
173
postlat = PsychPortAudio('LatencyBias', pahandle) %#ok<NOPRT,NASGU>
158
%mynoise = randn(2,freq * 0.1);
159
% Generate some beep sound 1000 Hz, 0.1 secs, 90% amplitude:
175
% Generate some beep sound 1000 Hz, 0.1 secs, 50% amplitude:
160
176
mynoise(1,:) = 0.5 * MakeBeep(1000, 0.1, freq);
161
177
mynoise(2,:) = mynoise(1,:);
178
194
% Check settings by printing them:
179
195
dpixstatus = Datapixx('GetMicrophoneStatus') %#ok<NOPRT,NASGU>
181
% Triggerlevel shall be 10% aka 0.1:
182
DatapixxAudioKey('TriggerLevel', 0.1);
184
% DataPixx: Setup Screen imagingpipeline to support measurement:
197
if ~(exactstart && isempty(triggerLevel))
198
if isempty(triggerLevel)
199
% Choose a default of 1% of max. signal amplitude:
202
fprintf('Using a trigger level for DataPixx of %f. This may need tweaking by you...\n', triggerLevel);
203
DatapixxAudioKey('TriggerLevel', triggerLevel);
206
% DataPixx: Setup Screen imagingpipeline to support measurement via the PSYNC
207
% video synchronization mode of DataPixx and Screen():
185
208
PsychImaging('PrepareConfiguration');
186
209
PsychImaging('AddTask', 'General', 'UseDataPixx');
187
210
win = PsychImaging('OpenWindow', screenid, 0);
190
213
% Default: No need for imaging pipeline:
191
214
win = Screen('OpenWindow', screenid, 0);
193
217
ifi = Screen('GetFlipInterval', win);
219
% Set waitframes to a good default, if none is provided by user:
220
if isempty(waitframes)
221
% We try to choose a waitframes that maximizes the chance of hitting
222
% the onset deadline. We are conservative in our estimate, because a
223
% few video refresh cycles hardly matter for this test, but increase
224
% our chance of success without need for manual tuning by user:
225
if isempty(suggestedLatencySecs)
226
% Let's assume 12 msecs on Linux and OSX as a achievable latency by
227
% default, then double it:
228
waitframes = ceil((2 * 0.012) / ifi) + 1;
230
% Whatever was provided, then double it:
231
waitframes = ceil((2 * suggestedLatencySecs) / ifi) + 1;
235
fprintf('\n\nWaiting %i video refresh cycles before white-flash.\n', waitframes);
237
% Auto-Selection of triggerLevel for Datapixx timestamping requested?
238
if useDPixx && exactstart && isempty(triggerLevel)
239
% Use auto-trigger mode. Tell the function how long the silence
240
% interval at start of each trial is expected to be. This will be
241
% used for calibration: We set it to 75% of the duration of the pause
242
% between start of Datapixx recording and scheduled sound onset time:
243
DatapixxAudioKey('AutoTriggerLevel', ifi * waitframes * 0.75);
244
fprintf('Setting lead time of silence in Datapixx auto-trigger mode to %f msecs.\n', ifi * waitframes * 0.75 * 1000);
247
% Perform one warmup trial, to get the sound hardware fully up and running,
248
% performing whatever lazy initialization only happens at real first use.
249
% This "useless" warmup will allow for lower latency for start of playback
250
% during actual use of the audio driver in the real trials:
251
PsychPortAudio('Start', pahandle, 1, 0, 1);
252
PsychPortAudio('Stop', pahandle, 1);
254
% Ok, now the audio hardware is fully initialized and our driver is on
255
% hot-standby, ready to start playback of any sound with minimal latency.
195
257
% Wait for keypress.
199
% Realtime scheduling:
260
% Realtime scheduling: Can be used if otherwise timing is not good enough.
200
261
% Priority(MaxPriority(win));
202
263
% Ten measurement trials:
205
% Start the playback engine with an infinite start deadline, ie.,
206
% start hardware, but don't play sound:
207
PsychPortAudio('Start', pahandle, 1, inf, 0);
209
% Wait a bit, say 100 msecs, so hardware is certainly running and settled:
213
266
% Schedule start of audio capture on DataPixx at next Screen('Flip'):
214
267
DatapixxAudioKey('CaptureAtFlip');
217
% This flip clears the display to black and returns timestamp of black
270
% This flip clears the display to black and returns timestamp of black onset:
271
% It also triggers start of audio recording by the DataPixx, if it is
272
% used, so the DataPixx gets some lead-time before actual audio onset.
219
273
[vbl1 visonset1]= Screen('Flip', win);
221
275
% Prepare black white transition:
223
277
Screen('DrawingFinished', win);
226
% Schedule start of audio at exactly the predicted visual
227
% stimulus onset caused by the next flip command:
228
PsychPortAudio('RescheduleStart', pahandle, visonset1 + waitframes * ifi, 0);
280
% Schedule start of audio at exactly the predicted visual stimulus
281
% onset caused by the next flip command.
282
PsychPortAudio('Start', pahandle, 1, visonset1 + waitframes * ifi, 0);
231
285
% Ok, the next flip will do a black-white transition...