function BasicSoundInputDemo(wavfilename, voicetrigger, maxsecs, device, reqlatencyclass, channels) % BasicSoundInputDemo([wavfilename][, voicetrigger=0][, maxsecs=inf][, device][, reqlatencyclass][, channels=2]) % % Demonstrates very basic usage of the new Psychtoolbox sound driver % PsychPortAudio() for audio capture / recording. % % Sound is captured from the default recording device, optionally waiting % until the amplitude exceeds some threshold level before start of % recording. At the end of the recording session the recorded sound is % played back vie the default output device. Waveform data of captured % sound is also plotted to a Matlab figure window during capture. % % This demo only demonstrates normal operation, not the low-latency mode, % extra demos and tests for low-latency and high precision timing output will % follow soon. If you need low-latency, make sure to read "help % InitializePsychSound" carefully or contact the forum. % % Optional arguments: % % wavfilename = Name of a .wav sound file to store the recorded sound to. % If left out, sound won't be stored to filesystem. % % voicetrigger = If set to a non-zero threshold value, the driver will wait % for the sound signal to exceed the specified voicetrigger threshold % level before it starts capturing audio data. % % maxsecs = Maximum number of seconds of sound to capture. Defaults to % infinite - sound is recorded until a key is pressed. % % device = Deviceindex of audio card to use. Auto-Selected if omitted. % % reqlatencyclass = Override reqlatencyclass parameter for audio capture. Defaults % to standard [] for low-latency, high timing precision if omitted. % % channels = Number of input and output channels to use. Defaults to 2. % % History: % 06/30/2007 Written (MK) % 08/10/2008 Add some sound onset time calculation for the fun of it. (MK) % 11/07/2018 Auto select samplerate, use low-latency, workaround Octave plotting, % allow 'device' selection. Cosmetic. (MK) % Running on PTB-3? Abort otherwise. PsychDefaultSetup(1); % Filename provided? if nargin < 1 wavfilename = []; end if nargin < 2 voicetrigger = []; end if isempty(voicetrigger) voicetrigger = 0; end if nargin < 3 maxsecs = []; end if isempty(maxsecs) maxsecs = inf; end if nargin < 4 device = []; end if nargin < 5 reqlatencyclass = []; end % If no specific reqlatencyclass is requested, but voicetrigger is wanted, raise % to level 2 - exclusive device access - for good timestamping and low latency: if isempty(reqlatencyclass) && (voicetrigger > 0) reqlatencyclass = 2; end if nargin < 6 || isempty(channels) channels = 2; end % Workaround broken qt plotting on some Octave setups: if IsOctave && exist('graphics_toolkit') %#ok try graphics_toolkit ('fltk'); catch end end % Wait for release of all keys on keyboard: RestrictKeysForKbCheck(KbName('ESCAPE')); KbReleaseWait; % Perform basic initialization of the sound driver: InitializePsychSound(double(reqlatencyclass > 1)); % Open audio device 'device', with mode 2 (== Only audio capture), % and a required latencyclass of 'reqlatencyclass', with the preferred % default sampling frequency of the audio device, and 'channels' sound channels % for stereo capture. This returns a handle to the audio device: pahandle = PsychPortAudio('Open', device, 2, reqlatencyclass, [], channels); % Get what freq'uency we are actually using: s = PsychPortAudio('GetStatus', pahandle); freq = s.SampleRate; % Preallocate an internal audio recording buffer with a 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); fprintf('Audio capture started, press any key for about 1 second to quit.\n'); % Want to start via VoiceTrigger? if voicetrigger > 0 % Yes. Fetch audio data and check against threshold: level = 0; % Repeat as long as below trigger-threshold: while level < voicetrigger % Fetch current audiodata: [audiodata, offset, ~, 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 < voicetrigger % Wait before next scan: WaitSecs(0.0001); end end % Ok, last fetched chunk was above threshold! % Find exact location of first above threshold sample. idx = min(find(abs(audiodata(1,:)) >= voicetrigger)); %#ok % Initialize our recordedaudio vector with captured data starting from % triggersample: recordedaudio = audiodata(:, idx:end); % For the fun of it, calculate signal onset time in the GetSecs time: tOnset = tCaptureStart + ((offset + idx - 1) / freq); fprintf('Estimated signal onset time is %f secs, this is %f msecs after start of capture.\n', tOnset, (tOnset - tCaptureStart)*1000); else % Start with empty sound vector: recordedaudio = []; end % We retrieve status once to get access to SampleRate: s = PsychPortAudio('GetStatus', pahandle); % Stay in a little loop until keypress: while ~KbCheck && ((length(recordedaudio) / s.SampleRate) < maxsecs) % Wait a second... WaitSecs(1); % Query current capture status and print it to the Matlab window: s = PsychPortAudio('GetStatus', pahandle); % Print it: fprintf('\n\nAudio capture started, press any key for about 1 second to quit.\n'); fprintf('This is some status output of PsychPortAudio:\n'); disp(s); % Retrieve pending audio data from the drivers internal ringbuffer: audiodata = PsychPortAudio('GetAudioData', pahandle); nrsamples = size(audiodata, 2); % Plot it, just for the fun of it: if channels > 1 plot(1:nrsamples, audiodata(1,:), 'r', 1:nrsamples, audiodata(2,:), 'b'); else plot(1:nrsamples, audiodata(1,:), 'r'); end drawnow; % And attach it to our full sound vector: recordedaudio = [recordedaudio audiodata]; %#ok end % Stop capture: PsychPortAudio('Stop', pahandle); % Perform a last fetch operation to get all remaining data from the capture engine: audiodata = PsychPortAudio('GetAudioData', pahandle); % Attach it to our full sound vector: recordedaudio = [recordedaudio audiodata]; % Close the audio device: PsychPortAudio('Close', pahandle); RestrictKeysForKbCheck([]); % Shall we store recorded sound to wavfile? if ~isempty(wavfilename) psychwavwrite(transpose(recordedaudio), freq, 16, wavfilename) end % Replay recorded data: Open 'device' for output, push recorded sound % data into its output buffer: pahandle = PsychPortAudio('Open', device, 1, 0, freq, channels); PsychPortAudio('FillBuffer', pahandle, recordedaudio); % Start playback immediately, wait for start, play once: PsychPortAudio('Start', pahandle, 1, 0, 1); % Wait for end of playback, then stop engine: PsychPortAudio('Stop', pahandle, 1); % Close the audio device: PsychPortAudio('Close', pahandle); % Done. fprintf('Demo finished, bye!\n');