Skip to content

Commit

Permalink
Sound input demos: Allow specification of number of input channels.
Browse files Browse the repository at this point in the history
For BasicSoundInputDemo and DelayedSoundFeedbackDemo, allow to specify the
number of inputs, to also deal with sound cards which only provide one mono input
channel. Continue to default to 2 stereo channels.
  • Loading branch information
kleinerm committed Mar 22, 2024
1 parent cca01ed commit c89e9aa
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 19 deletions.
26 changes: 18 additions & 8 deletions Psychtoolbox/PsychDemos/BasicSoundInputDemo.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function BasicSoundInputDemo(wavfilename, voicetrigger, maxsecs, device, reqlatencyclass)
% BasicSoundInputDemo([wavfilename][, voicetrigger=0][, maxsecs=inf][, device][, reqlatencyclass])
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.
Expand Down Expand Up @@ -32,6 +32,8 @@ function BasicSoundInputDemo(wavfilename, voicetrigger, maxsecs, device, reqlate
% 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)
Expand Down Expand Up @@ -77,8 +79,12 @@ function BasicSoundInputDemo(wavfilename, voicetrigger, maxsecs, device, reqlate
reqlatencyclass = 2;
end

if nargin < 6 || isempty(channels)
channels = 2;
end

% Workaround broken qt plotting on some Octave setups:
if IsOctave && exist('graphics_toolkit')
if IsOctave && exist('graphics_toolkit') %#ok<EXIST>
try
graphics_toolkit ('fltk');
catch
Expand All @@ -94,9 +100,9 @@ function BasicSoundInputDemo(wavfilename, voicetrigger, maxsecs, device, reqlate

% 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 2 sound channels
% 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, [], 2);
pahandle = PsychPortAudio('Open', device, 2, reqlatencyclass, [], channels);

% Get what freq'uency we are actually using:
s = PsychPortAudio('GetStatus', pahandle);
Expand All @@ -120,7 +126,7 @@ function BasicSoundInputDemo(wavfilename, voicetrigger, maxsecs, device, reqlate
% Repeat as long as below trigger-threshold:
while level < voicetrigger
% Fetch current audiodata:
[audiodata offset overflow tCaptureStart] = PsychPortAudio('GetAudioData', pahandle);
[audiodata, offset, ~, tCaptureStart] = PsychPortAudio('GetAudioData', pahandle);

% Compute maximum signal amplitude in this chunk of data:
if ~isempty(audiodata)
Expand Down Expand Up @@ -174,7 +180,11 @@ function BasicSoundInputDemo(wavfilename, voicetrigger, maxsecs, device, reqlate
nrsamples = size(audiodata, 2);

% Plot it, just for the fun of it:
plot(1:nrsamples, audiodata(1,:), 'r', 1:nrsamples, audiodata(2,:), 'b');
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:
Expand Down Expand Up @@ -202,7 +212,7 @@ function BasicSoundInputDemo(wavfilename, voicetrigger, maxsecs, device, reqlate

% Replay recorded data: Open 'device' for output, push recorded sound
% data into its output buffer:
pahandle = PsychPortAudio('Open', device, 1, 0, freq, 2);
pahandle = PsychPortAudio('Open', device, 1, 0, freq, channels);
PsychPortAudio('FillBuffer', pahandle, recordedaudio);

% Start playback immediately, wait for start, play once:
Expand Down
27 changes: 16 additions & 11 deletions Psychtoolbox/PsychDemos/DelayedSoundFeedbackDemo.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function DelayedSoundFeedbackDemo(reqlatency, duplex, freq, minLatency, device)
% DelayedSoundFeedbackDemo([reqlatency=150 ms][, duplex=0][, freq]=48000[, minLatency=10 ms][, device])
function DelayedSoundFeedbackDemo(reqlatency, duplex, freq, minLatency, device, channels)
% DelayedSoundFeedbackDemo([reqlatency=150 ms][, duplex=0][, freq]=48000[, minLatency=10 ms][, device][, channels=2])
%
% CAUTION: TEST TIMING OF THIS SCRIPT WITH MEASUREMENT EQUIPMENT IF YOU
% DEPEND ON ACCURATE FEEDBACK TIMING!!!
Expand Down Expand Up @@ -52,6 +52,8 @@ function DelayedSoundFeedbackDemo(reqlatency, duplex, freq, minLatency, device)
%
% 'device' Optional device index of soundcard to use.
%
% 'channels' Number of input and output channels to use. Defaults to 2.
%
% Specific tips for different setups:
%
% On OSX with builtin sound chip on Intel Macs, choose duplex = 0 for
Expand Down Expand Up @@ -159,13 +161,17 @@ function DelayedSoundFeedbackDemo(reqlatency, duplex, freq, minLatency, device)
% fail with an error if it can't achieve the most high-perf settings:
latmode = 4;

if nargin < 6 || isempty(channels)
channels = 2;
end

if (reqlatency == 0) && duplex
% Special case: Full-duplex mode with minimum latency. We bypass Matlab
% by activating PsychPortAudios full-duplex monitoring mode. The driver
% itself will feed back all captured sound to the outputs with lowest
% possible latency. However we don't have any control over latency or
% sound and this only works on full-duplex hardware...
pa = PsychPortAudio('Open', device, 4+2+1, latmode, freq, 2, [], minLatency);
pa = PsychPortAudio('Open', device, 4+2+1, latmode, freq, channels, [], minLatency);

% Now that the device is open, try to enable the "Zero latency direct input
% monitoring" feature of some subset of some sound cards.
Expand Down Expand Up @@ -239,12 +245,12 @@ function DelayedSoundFeedbackDemo(reqlatency, duplex, freq, minLatency, device)
if ~duplex
% Open the default audio device [], with mode 2 (== Only audio capture),
% and a required latencyclass of latmode == low-latency mode, as well as
% a frequency of freq Hz and 2 sound channels for stereo capture.
% a frequency of freq Hz and 'channels' sound channels for stereo capture.
% This returns a handle to the audio device:
painput = PsychPortAudio('Open', device, 2, latmode, freq, 2, [], minLatency);
painput = PsychPortAudio('Open', device, 2, latmode, freq, channels, [], minLatency);
else
% Same procedure, but open for full-duplex operation:
painput = PsychPortAudio('Open', device, 2+1, latmode, freq, 2, [], minLatency);
painput = PsychPortAudio('Open', device, 2+1, latmode, freq, channels, [], minLatency);
% Output- and input device are the same...
paoutput = painput;
end
Expand All @@ -254,9 +260,8 @@ function DelayedSoundFeedbackDemo(reqlatency, duplex, freq, minLatency, device)
PsychPortAudio('GetAudioData', painput, max(2 * lat, 10));

if ~duplex
% Open default audio device [] for playback (mode 1), low latency (2), freq Hz,
% stereo output:
paoutput = PsychPortAudio('Open', device, 1, latmode, freq, 2, [], minLatency);
% Open default audio device [] for playback (mode 1), low latency (2), freq Hz output:
paoutput = PsychPortAudio('Open', device, 1, latmode, freq, channels, [], minLatency);
end

% Get actually chosen sampling frequency:
Expand All @@ -268,7 +273,7 @@ function DelayedSoundFeedbackDemo(reqlatency, duplex, freq, minLatency, device)
% One could do this more clever, but this is a safe no-brainer and memory
% is cheap:
outbuffersize = floor(freq * 3 * max(lat, 10));
PsychPortAudio('FillBuffer', paoutput, zeros(2, outbuffersize));
PsychPortAudio('FillBuffer', paoutput, zeros(channels, outbuffersize));

% Start audio playback immediately, wait for the start to happen. Retrieve the
% start timestamp, ie., the system time when the first sample in the output
Expand Down Expand Up @@ -306,7 +311,7 @@ function DelayedSoundFeedbackDemo(reqlatency, duplex, freq, minLatency, device)
fprintf('CaptureQuantum (Duty cycle length) is %f msecs, for a buffersize of %i samples.\n', captureQuantum * 1000, s.BufferSize);
end

[audiodata offset overflow capturestart] = PsychPortAudio('GetAudioData', painput, [], captureQuantum);
[audiodata, offset, overflow, capturestart] = PsychPortAudio('GetAudioData', painput, [], captureQuantum);

% Sanity check returned values: audiodata should be at least headroom * s.BufferSize
% samples, offset should be zero as this is the first 'GetAudioData' call
Expand Down

0 comments on commit c89e9aa

Please sign in to comment.