~ubuntu-branches/ubuntu/trusty/psychtoolbox-3/trusty-proposed

« back to all changes in this revision

Viewing changes to Psychtoolbox/PsychTests/PsychPortAudioTimingTest.m

  • Committer: Package Import Robot
  • Author(s): Yaroslav Halchenko
  • Date: 2013-11-19 23:34:50 UTC
  • mfrom: (3.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20131119233450-f7nf92vb8qavjmk8
Tags: 3.0.11.20131017.dfsg1-3
Upload to unsable since fresh glew has arrived to sid!

Show diffs side-by-side

added added

removed removed

Lines of Context:
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])
3
3
%
4
4
% Test script for sound onset timing reliability and sound onset
5
5
% latency of the PsychPortAudio sound driver.
13
13
% speakers, some oszillograph to record and measure the signals from the
14
14
% diode and microphone.
15
15
%
16
 
% Some parameters may need tweaking. Make sure you got the special driver
17
 
% plugin as described in 'help InitializePsychSound' for best results.
18
 
%
19
 
% This is early alpha code, expect some rough edges...
 
16
% Some parameters may need tweaking. Make sure you got a setup as described
 
17
% in 'help InitializePsychSound' for best results.
20
18
%
21
19
% Optional parameters:
22
20
%
40
38
%                     audio onset time wrt. to visual stimulus onset.
41
39
%                0 -- Don't use DataPixx. This is the default.
42
40
%
 
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.
 
55
%
43
56
 
44
57
% Initialize driver, request low-latency preinit:
45
58
InitializePsychSound(1);
105
118
% Request latency mode 2, which used to be the best one in our measurement:
106
119
% classes 3 and 4 didn't yield any improvements, sometimes they even caused
107
120
% problems.
108
 
reqlatencyclass = 2; % class 2 empirically the best, 3 & 4 == 2
 
121
reqlatencyclass = 2;
109
122
 
110
123
% Requested output frequency, may need adaptation on some audio-hw:
111
124
freq = 44100;       % Must set this. 96khz, 48khz, 44.1khz.
113
126
suggestedLatencySecs = [];
114
127
 
115
128
if IsWin
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');
117
135
end
118
 
 
 
136
 
119
137
% Needs to determined via measurement once for each piece of audio
120
138
% hardware:
121
139
if nargin < 3 
133
151
    waitframes = [];
134
152
end
135
153
 
136
 
if isempty(waitframes)
137
 
    waitframes = 1;
138
 
end
139
 
 
140
 
waitframes %#ok<NOPRT>
141
 
 
142
154
if nargin < 5
143
155
    useDPixx = [];
144
156
end
147
159
    useDPixx = 0;
148
160
end
149
161
 
 
162
if nargin < 6
 
163
    % Default triggerLevel is "auto-trigger":
 
164
    triggerLevel = [];
 
165
end
 
166
 
150
167
% Open audio device for low-latency output:
151
168
pahandle = PsychPortAudio('Open', deviceid, [], reqlatencyclass, freq, 2, buffersize, suggestedLatencySecs);
152
169
 
155
172
prelat = PsychPortAudio('LatencyBias', pahandle, latbias) %#ok<NOPRT,NASGU>
156
173
postlat = PsychPortAudio('LatencyBias', pahandle) %#ok<NOPRT,NASGU>
157
174
 
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,:);
162
178
 
178
194
    % Check settings by printing them:
179
195
    dpixstatus = Datapixx('GetMicrophoneStatus') %#ok<NOPRT,NASGU>
180
196
 
181
 
    % Triggerlevel shall be 10% aka 0.1:
182
 
    DatapixxAudioKey('TriggerLevel', 0.1);
183
 
 
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:
 
200
            triggerLevel = 0.01;
 
201
        end
 
202
        fprintf('Using a trigger level for DataPixx of %f. This may need tweaking by you...\n', triggerLevel);
 
203
        DatapixxAudioKey('TriggerLevel', triggerLevel);
 
204
    end
 
205
    
 
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);
192
215
end
 
216
 
193
217
ifi = Screen('GetFlipInterval', win);
194
218
 
 
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;        
 
229
    else
 
230
        % Whatever was provided, then double it:
 
231
        waitframes = ceil((2 * suggestedLatencySecs) / ifi) + 1;
 
232
    end
 
233
end
 
234
 
 
235
fprintf('\n\nWaiting %i video refresh cycles before white-flash.\n', waitframes);
 
236
 
 
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);
 
245
end
 
246
 
 
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);
 
253
 
 
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.
 
256
 
195
257
% Wait for keypress.
196
 
while KbCheck; end;
197
 
KbWait;
 
258
KbStrokeWait;
198
259
 
199
 
% Realtime scheduling:
 
260
% Realtime scheduling: Can be used if otherwise timing is not good enough.
200
261
% Priority(MaxPriority(win));
201
262
 
202
263
% Ten measurement trials:
203
264
for i=1:10
204
 
 
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);
208
 
 
209
 
    % Wait a bit, say 100 msecs, so hardware is certainly running and settled:
210
 
    WaitSecs(0.1);
211
 
 
212
265
    if useDPixx
213
266
        % Schedule start of audio capture on DataPixx at next Screen('Flip'):
214
267
        DatapixxAudioKey('CaptureAtFlip');
215
268
    end
216
269
    
217
 
    % This flip clears the display to black and returns timestamp of black
218
 
    % onset:
 
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);
220
274
 
221
275
    % Prepare black white transition:
223
277
    Screen('DrawingFinished', win);
224
278
 
225
279
    if exactstart
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);
229
283
    end
230
284
 
231
285
    % Ok, the next flip will do a black-white transition...
234
288
    if ~exactstart
235
289
        % No test of scheduling, but of absolute latency: Start audio
236
290
        % playback immediately:
237
 
        PsychPortAudio('RescheduleStart', pahandle, 0, 0);
 
291
        PsychPortAudio('Start', pahandle, 1, 0, 0);
238
292
    end
239
293
 
240
294
    t2 = GetSecs;
252
306
        end
253
307
        WaitSecs('YieldSecs', 0.001);
254
308
    end
255
 
 
256
309
    audio_onset = status.StartTime;
257
 
    status.TotalCalls
258
310
 
259
311
    %fprintf('Expected visual onset at %6.6f secs.\n', visual_onset);
260
312
    %fprintf('Sound started between %6.6f and  %6.6f\n', t1, t2);
269
321
    fprintf('Expected audio-visual delay    is %6.6f msecs.\n', (audio_onset - visual_onset)*1000.0);
270
322
 
271
323
    if useDPixx
272
 
        % 'visonset1' is the GetSecs() time of start of capture on DataPixx.
273
 
        % 'audio_onset' is reported GetSecs() onset time according to PsychPortAudio.
 
324
        % 'visonset1' is the GetSecs() time of start of capture on
 
325
        % DataPixx. 'audio_onset' is reported GetSecs() audio onset time
 
326
        % according to PsychPortAudio.
274
327
        %
275
328
        % 'expectedAudioDelta' is therefore the expected delay for the
276
329
        % measured audio onset by DataPixx:
291
344
    % Stop playback:
292
345
    PsychPortAudio('Stop', pahandle, 1);
293
346
 
 
347
    % Wait a bit...
294
348
    WaitSecs(0.3);
295
349
 
296
350
    Screen('FillRect', win, 0);
297
351
    telapsed = Screen('Flip', win) - visual_onset; %#ok<NASGU>
298
352
    WaitSecs(0.6);
299
 
 
300
353
end
301
354
 
302
355
% Done, close driver and display: