/usr/share/psychtoolbox-3/PsychDemos/SimpleVoiceTriggerDemo.m is in psychtoolbox-3-common 3.0.14.20170103+git6-g605ff5c.dfsg1-1build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | function SimpleVoiceTriggerDemo(triggerlevel)
% SimpleVoiceTriggerDemo(triggerlevel)
%
% Demonstrates very basic usage of the new Psychtoolbox sound driver
% PsychPortAudio() for implementation of a "voice trigger". This really
% only collects the "voice response time" it doesn't actually store the
% resonse itself. Have a look at BasicSoundInputDemo for how one can
% actually retrieve and save the sound vector with the response itself.
%
% The script relies on well working sound cards and drivers. It should
% "just work" on most MacOS/X and Linux systems with standard hardware, but
% it will need special ASIO capable sound hardware on MS-Windows for
% accurate timing! See "help InitializePsychSound" for details.
%
% In any case you *must* verify correct timing of your sound hardware with
% some external measurement equipment, e.g., in conjunction with the
% PsychPortAudioTimingTest script (or the AudioFeedbackLatencyTest for a
% crude test). You only need to do this once after major changes to your
% systems software, hardware or Psychtoolbox installation, but there isn't
% any sane way to avoid such a validation!
%
% There are two different methods demonstrated to do so. Please read the
% source code of this file for details.
%
% In method I:
%
% The "response window" is fixed to 5 seconds. A trial will always last 5
% seconds, regardless if you respond early, late, or not at all.
%
%
% In method II:
%
% Sound is captured from the default recording device, waiting
% until the amplitude exceeds some 'triggerlevel'.
%
% If the triggerlevel is exceeded, sound capture stops, returning the
% estimated time of "voice onset" in system time.
%
% History:
% 08/10/2008 Written (MK)
if nargin < 1
triggerlevel = 0.1;
fprintf('No "triggerlevel" argument in range 0.0 to 1.0 provided: Will use default of 0.1...\n\n');
end
% Perform basic initialization of the sound driver, initialize for
% low-latency, high timing precision mode:
InitializePsychSound(1);
% Open the default audio device [], with mode 2 (== Only audio capture),
% and a required latencyclass of two 2 == low-latency mode, as well as
% a frequency of 44100 Hz and 2 sound channels for stereo capture. We also
% set the required latency to a pretty high 20 msecs. Why? Because we don't
% actually need low-latency here, we only need low-latency mode of
% operation so we get maximum timing precision -- Therefore we request
% low-latency mode, but loosen our requirement to 20 msecs.
%
% This returns a handle to the audio device:
freq = 44100;
pahandle = PsychPortAudio('Open', [], 2, 2, freq, 2, [], 0.02);
fprintf('\n\nPART I - Simple "offline" response collection at end of trial.\n');
fprintf('Each trials response period lasts 5 seconds...\n\n');
% FIRST METHOD: Supersimple
% This is suitable if the duration of the response collection period / the
% duration of a trial is fixed and if the script does not need to respond
% in any way to voice onset -- if the "voice trigger" is actually not
% triggering anything, but just the onset timestamp is of interest.
%
% In this case we simply start sound recording at the beginning of the
% trial - into a sound buffer of fixed and sufficient capacity.
% At the end of a trial (or a response period), we stop recording, fetch
% all audio data from the buffer (as well as a timestamp of when exactly
% recording was started), then use some simple Matlab thresholding code to
% find the first sample in the sound data vector which is above threshold,
% ie., the sample of response onset. Then we translate that samples index
% into a relative time to start of recording, add that to the absolute
% start time of recording, and get the absolute system time of voice onset,
% which we can log, or compare to other timestamps from Screen('Flip'),
% GetSecs, whatever to compute reaction times.
% Preallocate an internal audio recording buffer with a generous capacity
% of 10 seconds: We only need about 5 seconds, but let's be generous...
PsychPortAudio('GetAudioData', pahandle, 10);
% Do five trials:
for trial = 1:5
% Start audio capture immediately and wait for the capture to start.
% We set the number of 'repetitions' to zero, i.e. record until recording
% is manually stopped.
PsychPortAudio('Start', pahandle, 0, 0, 1);
% Tell user to shout:
fprintf('Make noise! Make noise! ');
tStim = GetSecs;
% Wait for about 5 seconds, so user has time to shout:
WaitSecs(5);
% Stop sound capture: End of response period.
PsychPortAudio('Stop', pahandle);
% Fetch all about 5 seconds of audiodata at once:
[audiodata offset overflow tCaptureStart]= PsychPortAudio('GetAudioData', pahandle);
% Ok, last fetched chunk was above threshold!
% Find exact location of first above threshold sample.
idx = min(find(abs(audiodata(1,:)) >= triggerlevel)); %#ok<MXFND>
% Any response?
if isempty(idx)
fprintf('No response at all within 5 seconds?!?\n\n');
else
% Compute absolute event time:
tOnset = tCaptureStart + ((offset + idx - 1) / freq);
% Print RT:
fprintf('---> Reaction time is %f milliseconds.\n', (tOnset - tStim)*1000);
end
% Next trial after 2 seconds:
WaitSecs(2);
end
% Done with method I. You'd now close the audio device, but we'll do that
% at the end of this script instead...
% =========================================================================
% SECOND METHOD: Slightly more elaborate
% The principle is the same as in method I, but now we don't analyze the
% whole chunk of audio data at the end of trial, but we implement some
% polling loop which periodically fetches small consecutive chunks of sound
% data and does the analysis. This way, response collection / stimulus
% presentation / whatever can be stopped as soon as we have our voice onset
% timestamp --> The voice trigger can actually really trigger some action
% in our script! This also allows for "infinite" response collection -- as
% we're only chewing on small chunks of audio data, the total duration of
% response collection is not in any way limited by available memory or
% such.
fprintf('\n\nPART II - The saga continues... This time with a polling method.\n\n');
% Do ten trials:
for trial = 1:10
% Preallocate an internal audio recording buffer with a generous capacity
% of 10 seconds:
PsychPortAudio('GetAudioData', pahandle, 10);
% Start audio capture immediately and wait for the capture to start.
% We set the number of 'repetitions' to zero, i.e. record until recording
% is manually stopped.
PsychPortAudio('Start', pahandle, 0, 0, 1);
% Tell user to shout:
fprintf('Make noise! Make noise! ');
tStim = GetSecs;
% Wait in a polling loop until some sound event of sufficient loudness
% is captured:
level = 0;
% Repeat as long as below trigger-threshold:
while level < triggerlevel
% Fetch current audiodata:
[audiodata offset overflow tCaptureStart]= PsychPortAudio('GetAudioData', pahandle);
% Compute maximum signal amplitude in this chunk of data:
if ~isempty(audiodata)
level = max(abs(audiodata(1,:)));
else
level = 0;
end
% Below trigger-threshold?
if level < triggerlevel
% Wait for five milliseconds before next scan:
WaitSecs(0.005);
end
end
% Ok, last fetched chunk was above threshold!
% Find exact location of first above threshold sample.
idx = min(find(abs(audiodata(1,:)) >= triggerlevel)); %#ok<MXFND>
% Compute absolute event time:
tOnset = tCaptureStart + ((offset + idx - 1) / freq);
% Stop sound capture:
PsychPortAudio('Stop', pahandle);
% Fetch all remaining audio data out of the buffer - Needs to be empty
% before next trial:
PsychPortAudio('GetAudioData', pahandle);
% Print RT:
fprintf('---> Reaction time is %f milliseconds.\n', (tOnset - tStim)*1000);
% Next trial after 2 seconds:
WaitSecs(2);
end
% Close the audio device:
PsychPortAudio('Close', pahandle);
% Done.
fprintf('Demo finished, bye!\n');
return;
|