Playing a given sound from a given speaker

Hello,


I'm using Asio SoundCard with Motu driver and have 3 Speaker. I want to specify at a given time whether the sound will be played on Speaker 1 / 2 / 3  .


How could I specify which Speaker should be used (numbers ? physical adress? )


I'm using the function below , I've an output I think from the first Speaker even of the three speaker are plugged :



function BasicMultiSoundOutputDemo(repetitions, wavfilename)


AssertOpenGL;


repetitions=2

wavfilename='1.wav'


    % Read WAV file from filesystem:

    [y, freq ] = wavread(wavfilename);

    wavedata = y';

    nrchannels = size(wavedata,1); % Number of rows == number of channels.




% Open sound card

InitializePsychSound();

devices = PsychPortAudio('GetDevices');

nDevices = numel(devices);

% Found MOTU ASIO

MOTUASIOIndice = [];

for deviceIndex = 1:nDevices

    %fprintf(1, 'Examining device %s\n', outputDevices(deviceIndex).DeviceName);

    if strcmp(devices(deviceIndex).DeviceName, 'MOTU Audio ASIO')

        fprintf('Found MOTU ASIO device\n');

        MOTUASIOIndice = deviceIndex;

        disp(devices(MOTUASIOIndice));

        break;

    end

end

if isempty(MOTUASIOIndice)

    ME = MException('Experience_Contol:MOTUSoundCardNotFound', 'Can''t find MOTU sound card\n Check that it is plugged and that ASIO drivers are installed');

    throw(ME);

end;

MOTUASIODevice = devices(MOTUASIOIndice);

disp(MOTUASIODevice.DeviceIndex)


pahandle2 = PsychPortAudio('Open', 1, [], 1, freq, nrchannels);


% Fill the audio playback buffer with the audio data 'wavedata':

PsychPortAudio('FillBuffer', pahandle2, wavedata);



t1 = PsychPortAudio('Start', pahandle2, repetitions, 0, 1);


% Wait for release of all keys on keyboard:

KbReleaseWait;


fprintf('Audio playback started, press any key for about 1 second to quit.\n');

fprintf('Will play a beep tone of 0.1 secs duration every second.\n');


tlast = t1 + 4;


% Stay in a little loop until keypress:

while ~KbCheck

    when = tlast + 1;

    tlast = PsychPortAudio('Start', pahandle2, 1, when, 1);

    fprintf('Delta between onset of this beep and onset of sound track is %f secs.\n', tlast - t1);

    s = PsychPortAudio('GetStatus', pahandle2);

    PsychPortAudio('Stop', pahandle2, 1); 

    PsychPortAudio('FillBuffer', pahandle2, wavedata);

end

% Stop playback of background sound track:

PsychPortAudio('Stop', pahandle2);


% Close the audio devices:

PsychPortAudio('Close', pahandle2);

%PsychPortAudio('Close', pahandle2);


% Done.

fprintf('Demo finished, bye!\n');


Thanks for help


Lenar


each output from your audio interface is a separate channel, so the first thing is you should setup the audio device with the correct number of channels. usually you do not want to use the number of channels in the audio file to determine the number of device audio channels to open, which is one mistake in your code. your WAVE file is likely to be either mono or stereo, so you are opening the audio interface in only one or two channel mode.

once you have the audio device opened correctly, you specify which output channels to use by putting data in the appropriate rows of the audio data that you fill the buffer with. for example, if you want the sound to come from channel 3, then you put the signal in row 3, and zeros in the other rows.



---In PSYCHTOOLBOX@yahoogroups.com, <lenarell@...> wrote :

Hello,


I'm using Asio SoundCard with Motu driver and have 3 Speaker. I want to specify at a given time whether the sound will be played on Speaker 1 / 2 / 3  .


How could I specify which Speaker should be used (numbers ? physical adress? )


I'm using the function below , I've an output I think from the first Speaker even of the three speaker are plugged :



function BasicMultiSoundOutputDemo(repetitions, wavfilename)


AssertOpenGL;


repetitions=2

wavfilename='1.wav'


    % Read WAV file from filesystem:

    [y, freq ] = wavread(wavfilename);

    wavedata = y';

    nrchannels = size(wavedata,1); % Number of rows == number of channels.




% Open sound card

InitializePsychSound();

devices = PsychPortAudio('GetDevices');

nDevices = numel(devices);

% Found MOTU ASIO

MOTUASIOIndice = [];

for deviceIndex = 1:nDevices

    %fprintf(1, 'Examining device %s\n', outputDevices(deviceIndex).DeviceName);

    if strcmp(devices(deviceIndex).DeviceName, 'MOTU Audio ASIO')

        fprintf('Found MOTU ASIO device\n');

        MOTUASIOIndice = deviceIndex;

        disp(devices(MOTUASIOIndice));

        break;

    end

end

if isempty(MOTUASIOIndice)

    ME = MException('Experience_Contol:MOTUSoundCardNotFound', 'Can''t find MOTU sound card\n Check that it is plugged and that ASIO drivers are installed');

    throw(ME);

end;

MOTUASIODevice = devices(MOTUASIOIndice);

disp(MOTUASIODevice.DeviceIndex)


pahandle2 = PsychPortAudio('Open', 1, [], 1, freq, nrchannels);


% Fill the audio playback buffer with the audio data 'wavedata':

PsychPortAudio('FillBuffer', pahandle2, wavedata);



t1 = PsychPortAudio('Start', pahandle2, repetitions, 0, 1);


% Wait for release of all keys on keyboard:

KbReleaseWait;


fprintf('Audio playback started, press any key for about 1 second to quit.\n');

fprintf('Will play a beep tone of 0.1 secs duration every second.\n');


tlast = t1 + 4;


% Stay in a little loop until keypress:

while ~KbCheck

    when = tlast + 1;

    tlast = PsychPortAudio('Start', pahandle2, 1, when, 1);

    fprintf('Delta between onset of this beep and onset of sound track is %f secs.\n', tlast - t1);

    s = PsychPortAudio('GetStatus', pahandle2);

    PsychPortAudio('Stop', pahandle2, 1); 

    PsychPortAudio('FillBuffer', pahandle2, wavedata);

end

% Stop playback of background sound track:

PsychPortAudio('Stop', pahandle2);


% Close the audio devices:

PsychPortAudio('Close', pahandle2);

%PsychPortAudio('Close', pahandle2);


% Done.

fprintf('Demo finished, bye!\n');


Thanks for help


Lenar


Thanks for your reply. 

There's still a question if I don't use a ".wav" file. I'm generating noise through the function below. When I use Y in the buffer, I've a matrix size matching problem (1*22198)
How can I use these signals ?

function [y] = makeNoise1(L_dB, D, fs, fc, N);

%See also makeTone
%
%J?rg Buchholz, V1.0, 17/5/2004
tic
fs=44100;
% D=2000
% L_dB=90
s = [zeros(round(.001*fs),1) ; randn(round(D*fs/1000),1) ; zeros(round(.001*fs),1)] ;
if nargin < 4;%broadband noise
    g = 10.^((L_dB-105)/20);%L_dB = 105dB equals sqrt(1/length(y)*sum(y.^2)) = 1
    y = g*s;
elseif nargin >= 4;%narrow band noise
    if length(fc) == 1;%gammatone BP filter is used
        [fcoefs]=MakeERBFilters(fs,[fc fc]);
        fcoefs = fcoefs(1,:);
        s = erbfilterbank(s,fcoefs);
        f_B = 6.23*1e-6*fc.^2 + 93.39*1e-3*fc + 28.52;%Bandwidth (Hz)
    elseif length(fc) == 2;%butterworth BP filter is used
        if nargin == 4;
            N = 5;%Default filter order
        end
        [B,A] = butter(N,[fc(1) fc(2)]/fs*2);
        s = filter(B,A,s);
        f_B = fc(2)-fc(1);%Bandwidth (Hz)
    else
        error('The input parameter fc has wrong size!')
    end
    L_dB = L_dB + 10*log10(fs/2/f_B);%equalize the bandwidth influence on the overall signal level
    g = 10.^((L_dB-105)/20);%L_dB = 105dB equals sqrt(1/length(y)*sum(y.^2)) = 1
    y = g*s;
end
sound(y,fs)
if max(abs(y)) > 1;
    warning('The signal amplitude exceeds the *.wav limits!')
end

Thanks
Lenar
for 3 channel output, you can just make a 3 row matrix of zeros that is the same length as your generated signal. then copy your signal into whichever row (channel) that you want the sound to play from...
You probably want to look at the help output of 'PsychPortAudio OpenSlave?' and at BasicAMAndMixScheduleDemo.m

It demonstrates a very effective/convenient way of doing what you want - treating each channel/speaker of a soundcard as an individually controllable sound card.

Other than that the code you posted spends lots of effort finding the deviceIndex of your Motu card, but then instead opens the card with the hardcoded device index 1? PsychPortAudio('GetDevices', 3) will already filter for only ASIO capable cards, and you should select from that smaller list for devices with an dev.NrOutputChannels >= 3.

The help in 'PsychPortAudio Open?' will also introduce you to the 'selectChannels' parameter which allows to select the subset of channels on a asio card you actually want to use.

-mario
i've never used it before, but that slave stuff does look handy for some things, thanks for pointing it out.

for multichannel output with very precise timing needs, i presume you would still be better of building your output as multi-row arrays though, rather than firing off multiple slave channels.


---In PSYCHTOOLBOX@yahoogroups.com, <mario.kleiner@...> wrote :

You probably want to look at the help output of 'PsychPortAudio OpenSlave?' and at BasicAMAndMixScheduleDemo.m

It demonstrates a very effective/convenient way of doing what you want - treating each channel/speaker of a soundcard as an individually controllable sound card.
No. The timing precision is identical. Internally there is only one thread per 'open'ed hardware soundcard which executes the code of each virtual soundcard as if it were a separate entity with its own state, sound buffers, etc., and then mixes the output of all those virtual slave soundcards into the output of the real master soundcard. Therefore the timing of all slaves is synchronized sample-accurate to each other and the actual hardware master soundcard.

Use of cpu is mostly identical. You pay a bit of time for mixing the audio, but not much. E.g., i tested this with a dual core 2007 MacBookPro and it could handle 64 simultaneous virtual soundcards mixed into one real card without trouble.

-mario
okay, good to know. i'll check it out in more detail. sounds even more handy.
Thanks a lot for all these useful information ,

However, how to avoid the following error if I want to make several trials of sound play,

PTB-ERROR: Failed to open audio device 2. PortAudio reports this error: Device unavailable 
INTERNAL PSYCHTOOLBOX ERROR
error:                PsychError_system
general description:  Error reported by a system call
specific description: Failed to open PortAudio audio device.
module name:          PsychPortAudio
subfunction call:     Open
file name:            Common\PsychPortAudio\PsychPortAudio.c
function name:        UNKNOWN
line number:          2353
Error using PsychPortAudio
See error message printed above.

Error in MT_measure_GUI_2>figure1_KeyPressFcn (line 371)
            pamaster = PsychPortAudio('Open', [], 1+8, 1, handles.Fs, nrchannels, [], sugLat,0);
 
Thanks again,

Lenarell

ps : I don't have this error the first time, but have it if I want to do a second trial.

Lenarell
You are probably reopening the device for each trial. If it is already open, you can't open it again


On Thu, May 15, 2014 at 4:19 AM, lenarell@... [PSYCHTOOLBOX] <PSYCHTOOLBOX@yahoogroups.com> wrote:


ps : I don't have this error the first time, but have it if I want to do a second trial.

Lenarell