I want to use PsychPortAudio to play sound in 24Ao Motu sound card. we have 24 Speaker and we want to play mono sound in one speaker anytime. I know ASIO is supported by Motu, and find Motu in asioseetings(), when install ASIO4ALL. I find 24 output channels through WASAPI and MME and WDM in PsychPortAudio(‘GetDevices’). but when in pahandle = PsychPortAudio(‘[Open][, deviceid][, mode][, reqlatencyclass][, freq][, channels][, buffersize][, suggestedLatency][, selectchannels][, specialFlags=0]); set the deviceid to WASAPI or WDM id num, we have error and when set to MME id we can use two channel.
may matlab version is R2020a and psychtoolbox is 3.0.18.
You need to provide more information. What error? What (exact) operating system+version?
system type:64-bit os, x64- based processor, windows 10 21H2, LTSC. MATLAB2021a
when used asiosettings we can see MOTU PRO Audio OUt1-24
devices = PsychPortAudio(‘GetDevices’)
nDevices = numel(devices);
see pic 1
in DeviceIndex we have 3 rows with NrOuputChannels=24. 5, 7, 16.
when used pahandle2 = PsychPortAudio(‘Open’, 5 , 1, 1, 48000,1,,,3,0);
we don’t have error but speaker3 output map to speaker 1.
but in DeviceIndex =7 with WASAPI we have this error
see Pic 2
and in but in DeviceIndex =16 with WDM-KS we see Pic 3
with changing HostAudio to ASIO and Device name to Out1-24 Pro MOTU Audio noting chanenged.
see Pic 4
Thanks for help.
system type:64-bit os, x64- based processor, windows 10 21H2, LTSC. MATLAB2021a
Congratulations, due to it being of general enough interest, your issue has been selected by myself for “free support on resolving a non-trivial issue”, sponsored by Mathworks Neuroscience - MATLAB and Simulink Solutions - MATLAB & Simulink - You get advice for free that would normally have cost your lab in excess of 1000 Euros. Mathworks provided us with 3 such “Jokers” for free support and you get to use the first out of three.
I’ve spent a couple of hours looking at this, and these are my findings of why your approach didn’t work and what one could do about it. Skip over this section if you want to get to my advice of what you should probably do instead of trying to fix your current approach:
- Channel mapping via the optional
selectchannelsparameter is currently only supported on:
- Apple macOS, where it at least works with the Mac internal stereo sound chip and speakers.
- In theory with MS-Windows with WASAPI sound backend, with limitations.
Because it isn’t supported on Windows with MME, DirectSound or WDM-KS audio backends, the parameter there is silently ignored and does not have an effect. On Linux it isn’t implemented either and would be silently ignored at the moment.
So that’s why you can open a sound device under MME or WDM-KS, but channel 1 is always used, as the parameter does not have an effect.
Under WASAPI, the situation is more complicated:
Due to Windows operating system limitations, one can only define channel mapping for output/playback, not for capture. The parameter is ignored for capture.
Due to Windows operating system limitation, one can not actually select which Portaudio channel (== sound matrix row) goes to which speaker, only which subset of speakers to use. In practice this means the order of elements in the
selectchannelsrow vector is ignored and the
selectchannelsvector is always treated as if sorted in ascending order, e.g.
[2,1,5,4,0]would turn into
[0,1,2,4,5]. In your case of only one channel mono playback, this would still work, selecting one physical speaker (Numbering starts at 0!).
In practice, testing on WASAPI with 1 channel mono on both the builtin soundchip of a Windows 10 and of a Windows 11 machine, and also with a cheap stereo USB soundcard on Windows 11, trying to replicate your method, channel mapping did not actually work. Low level debugging showed that the sound driver accepted the channel mapping, but then completely ignored it. When i opened 1 channel mono, sound was always output identical to both stereo outputs. So apparently it is up to the specific sound hardware and device driver if
selectchannelshas any effect on WASAPI or not. One might hope that a more expensive / pro soundcard like your Motu 24Ao might behave better, but that isn’t a guarantee.
Another design limitation of WASAPI, according to Microsoft docs, seems to be that often you can only open a soundcard with the number of
channelsthat matches its
NrOuputChannels, so it may be impossible to open your
DeviceIndex = 724 channel device for 1 channel mono output. One special case implemented in the Portaudio library is that if you try to open 1 channel mono on a
NrOutputChannels == 2stereo card, the driver handles that special case by configuring the card for stereo output and then internally upmixes your mono sound to stereo sound with identical content in both audio channels. This is the only exception implemented if the low-level audio device driver of your Motu does not handle this, and the specific error message which i correlated with portaudio source code, suggests your Motu can’t do this 1 channel output to the 24 channel device.
What might work is to instead open your 24Ao with (in your example)
DeviceIndex=8for the “Speakers (MOTU…” device with
NrOutputChannels == 2. As the MOTU is exposed as WASAPI 2 channel stereo output device, Portaudio should handle this 1 → 2 special case. Then you could see if the MOTU driver is clever enough to support the
selectchannelsparameter in that configuration. Another thing one could try is to set the
PsychPortAudio('Open', ...)to 2 or 3, to push for lower latency mode. This will switch the WASAPI device from “shared mode” to “exclusive mode” and fundamentally change the mode of operation and rules. Most likely this will also fail, but it is worth a try if you want to go this route.
Running all these tests with a
PsychPortAudio('Verbosity', 10);would provide more low-level debug information on what’s going on.
To summarize, use of
selectchannels, although it looks elegant, has multiple problems, which make it probably not the right approach to solving your problem:
selectchannelsis unsupported on Linux, Windows MME/WDM-KS, and generally poorly supported / unreliable / fiddly on Windows WASAPI on common sound hadware. This will make your script highly non-portable across operating systems and different models of sound cards.
- It has many limitations even on a soundcard where it supposedly works on Windows/WASAPI, severely restricting the flexibility of the approach.
Also, if you wanted to change the output speaker on a trial-by-trial basis in your experiment, calling
PsychPortAudio('Close') every trial makes for a complex script and lots of overhead. Open is meant to be called infrequently, ideally only once per session during experiment script startup.
A better solution which should work exactly the same on any operating system and sound card, with low overhead is to use PsychPortAudio audio slave devices instead:
- At the beginning of your script open the sound card with output to all 24 channels, but as a “master device” (+8 for mode) in low-latency/high-timing precision mode (reqlatencyclass >= 1) to host the virtual slave audio devices:
pamaster = PsychPortAudio('Open', , 1+8, 1, ...); PsychPortAudio('Start', pamaster);
this will auto-select a WASAPI audio device on Windows. It may be neccessary to specify the
channelsparameter as 24 to make sure the 24-channel variant is selected instead of the 2 channel variant.
- Inside your trial loop / whenever you want to select one mono channel output to one speaker, you create a 1-channel mono slave output device and attach it to the wanted target speaker output channel of the master device. E.g., for output to the speaker with index
selectchannel, you’d do:
paout = PsychPortAudio('OpenSlave', pamaster, 1, 1, selectchannel);
This creates paout, for playback (1) with 1 channel mono (1) attached to output channel number
selectchannelof the pamaster device and thereby speaker output channel
selectchannelof your sound card. Numbering of outputs for such slaves is 1-based, e.g…,
selectchannel = 1for speaker output 1. Then you use the
paoutdevice as you’d use normally. When you want to switch to a different speaker output, you
PsychPortAudio('Close', paout);, set a new
selectchannelvalue for the new speaker, and repeat this step 2 with
paout = PsychPortAudio('OpenSlave', ...);.
If you wanted to output the same sound vector
signalin successive trials, just to different speakers, you could use
PsychPortAudio('FillBuffer', paout, signal);as usual after each OpenSlave, but you could also pre-create all sound buffers via
bufferhandle = PsychPortAudio('CreateBuffer', , signal);
during session setup, and then just pass
bufferhandleto FillBuffer in the trial loop, ie.
PsychPortAudio('FillBuffer', paout, bufferhandle);.
The latter method is more efficient/elegant. Opening and closing such slave devices to switch channel output quickly is also very efficient/fast, on the order of a millisecond instead of possibly dozens or hundreds of milliseconds. Also less debug output clutter and more robust if other audio applications may be running.
- At the end of a session you can close all audio devices at once via a
A new demo in a future PTB beta release will demonstrate this. For now you can get the demo from this link:
This mechanism allows mixing and independent control of many parallel sounds, with independent channel assignments, start/stop times, schedules, AM modulation envelopes etc. Examples of use of such audio slave devices are to be found in
BasicAMAndMixScheduleDemo.m' or BasicSoundScheduleDemo.m
, or TurnTableDemo.m`.
As a slight variant, you could open one slave device attached to each output speaker channel, e.g., like this, and could play sound through each speaker, e.g.,
During script startup after creating
soundbufferhandle = PsychPortAudio('CreateBuffer', , signal); for i=1:24 % Attach i'th audio slave device to output speaker channel i: paout(i) = PsychPortAudio('OpenSlave', pamaster, 1, 1, i); % Use same sound 'signal' for each output device: PsychPortAudio('FillBuffer', paout(i), soundbufferhandle); end
… later on inside trial loop, play sound for speaker i:
… or for speakers [1,4,5] simultaneously all starting one second from now, ie.
GetSecs + 1:
tStart = GetSecs + 1; for i=[1,4,5] PsychPortAudio('Start', paout(i), , tStart); end
The downside of the proposed approach instead of using ‘selectchannels’ is that our driver always has to drive all 24 channels of the hardware, even if only outputting 1 channel mono sound, causing a potentially higher system load, because all mixing and remapping is done internal to PsychPortAudio, not by the audio hardware. However, modern computers are fast, and shouldn’t break a sweat for, e.g., 24 channels. I tested some of this on machines over ten years ago with 64 channels and it wasn’t an issue.
Btw. Psychtoolbox does not support ASIO™ [Disclaimer: “ASIO™ is a trademark and software of Steinberg Media Technologies GmbH.”] out of the box anymore, the reasons for this are explained in “System Requirements” on our Website. Therefore ASIO4All will have no effect, neither will any other ASIO driver, and ASIO remains inaccessible by a standard Psychtoolbox setup. However, as your MOTU card likely comes with native ASIO drivers, you wouldn’t need ASIO4All for that card, as it is meant to implement a best effort “fake ASIO” on incapable sound hardware.
That said, your debug output tipped me off to a way you might be able to use at least basic ASIO under modern Matlab + PsychPortAudio without the need for PsychPortAudio / Psychtoolbox to actually implement support for it. Some Matlab compatibility fixes will be in an upcoming Psychtoolbox 3.0.19 release to allow PsychPortAudio to use the portaudio.dll provided by Matlab itself. However, this doesn’t really change recommendations for your specific use case, as using audio slave devices is a better solution.
Hope this helps,
I was very surprised. The solutions were excellent. I used all of them.
I appreciate your swift reply.
Good. Mathworks will be pleased their money didn’t go to a waste.
Did you also successfully try opening you 23Ao with the
DeviceIndex=8 for the “Speakers (MOTU…” device with
NrOutputChannels == 2? Would be interesting to know how MOTU fares there, even though the method with the audio slave devices is the recommended one for your use case.