couple psychportaudio feature requests

hey mario-
i have a couple feature requests for psychportaudio:

1) allow 'start' to take a non-integer number of repetitions
reason: i preload my buffers before my realtime screen loop to avoid
framedrops. within the loop, i need to be able to play sounds whose
durations are not determined until just before they start. i want to
avoid the framedrops that might result from having to create a new
buffer of the proper length. the sound duration may outlast the
realtime loop, so i can't just loop the sound, keep track of the
elapsed time, and stop it myself (which would unnecessarily clutter
the code anyway).

2) allow sequential calls to 'start' with no intervening 'stop', with
each call resetting the 'repetitions' parameter (ie, start over from
the beginning as if there were a 'stop' immediately followed by a
'start' with a new 'repetitions' parameter.)
reason: convenience. currently, one must call stop even if a finite
sound has completed, and keep track of the sound status manually, to
determine whether a 'stop' is necessary. plus, requiring a manual
'stop' eliminates the possibility of deciding to lengthen a sound once
it has started without an undesired gap.

3) automatically 'stop' a finite sound that has completed, including
unsetting status.Active (currently it remains set until 'stop' is
called manually).

let me know if these sound reasonable, and thanks again for the
excellent ptb!
-erik
hmm, two more, but i understand if they're not realistic.

1) i can't get 'stop' to return any faster than 10ms (and it's usually
up to 30ms), on my osx box or any of 4 different windows setups,
including one with a native asio card, using either the regular or
enhanced dll's, initializepsychsound(1) or (0), and a variety of
reqlatencyclass and buffersize settings. those times guarantee frame
drops -- any hope of getting it down around 1ms? on two of the
windows setups (but not osx), matlab's audioplayer's start and stop
both return in around 3ms (in my present situation, this is more
important than the latency to actual sound onset/offset).

2) under windows with the enhanced dll, even on the setup with the
native asio card, i can't get more than one pahandle open, no matter
what the reqlatencyclass. on osx and under windows with the
unenhanced dll i can open around 9. any chance of allowing this under
the enhanced dll?

-e
> 1) i can't get 'stop' to return any faster than 10ms

apologies -- it's under 1ms on my setup with an asio card. but not on
osx... (forgot to mention i *am* setting waitForEndOfPlayback to 2)

> 2) under windows with the enhanced dll, even on the setup with the
> native asio card, i can't get more than one pahandle open, no matter
> what the reqlatencyclass. on osx and under windows with the
> unenhanced dll i can open around 9. any chance of allowing this under
> the enhanced dll?

i looked through the code here:
http://svn.berlios.de/wsvn/osxptb/beta/PsychSourceGL/Source/Common/PsychPortAudio/PsychPortAudio.c

and see that you have:
#define MAX_PSYCH_AUDIO_DEVS 10

this is what causes the limit under the non-enhanced dll. 10 is
enough for my current application, i am just curious why a fixed limit
is necessary?

in the enhanced case, the Pa_OpenStream call is apparently returning
paDeviceUnavailable.

i looked into the portaudio code, and in pa_asio.cpp in OpenStream()
it notes:
/* unless we move to using lower level ASIO calls, we can only
have one device open at a time */

it's too bad, cuz it's nice to have multiple different sounds
'fillbuffered' up and ready to 'start' with as little latency as
possible...
-e
Hi Erik,

the limit is because PsychPortAudio is not meant
to be used that way, even if it works to some
degree on some setups, e.g., on OS/X or on
Windows and Linux in "high latency mode".

Each open audio device / pahandle consumes
some system ressources. Depending on how
many devices you open and on the specifics
of the operating system,audio driver and hardware,
this can turn into a performance or timing problem.

The ASIO limit of 1 open device (and a similar limit
on Linux+ALSA in low-latency mode) is by design
of the drivers and hardware. It is not easy to overcome,
even if the portaudio devs would "move to lower level calls"
as the comment suggests, that wouldn't help on
most cards and drivers, they would just hit the
next brick wall at a lower level, except for maybe
a few very expensive very pro sound cards, so
in that sense its not worth it to remove that limit
from portaudio.

Btw. the enhanced dll is just extended with asio wrt. to
the standard dll, so if you don't choose low-latency
mode with the enhanced dll, and/or specify
the 'device' in 'Open' directly, you can choose
a different output device than asio and it will
behave just like the standard dll.

I've extended the new driver per your suggestions,
which should improve latency and usability:

* No need to call 'Stop' anymore, playback stops
by itself (unless infinite repetitions are selected).

* A new flag for 'Stop' named 'blockUntilStopped':
If set to zero, the 'Stop' method will return as soon
as possible, because after issuing a stop request,
it doesn't wait for the stop to actually happen anymore.

* A new optional parameter 'stopTime' for the 'Start'
method and the 'Stop' method: Like the 'when' parameter,
but you can define requested audio offset time beforehand.
You could set number of repetitions to "endless" or a
high value, then use that time parameter to request
sound offset at a specific time.

* Fractional values for 'repetitions'.

* For very fast/low latency starting and stopping of
sounds, you can use the new 'RunMode' subfunction
to switch the driver into runMode 1, instead of the
default runMode 0. In runMode 1, the audio engine
keeps running all the time, once started and just
"virtually" stops playback by outputting a constant
audio strem of silence. This avoids the regular start/
stop overhead of the audio hardware and allows for
faster stop/restart cycles. The downside is permanent
use of a bit of cpu time or the production of silence.
This runMode 1 should be especially effective on
Linux, where stop/restart latency is quite high, but
it also helps on OS/X or Windows.

* Then there is a new command 'RefillBuffer' to refill
part of an audio buffer while a different part of the
buffer is played out, and the command 'SetPlayLoop'
to only play out parts of an audio buffer.

* And playlist support: New functions 'UseSchedule'
and 'AddToSchedule' allow to define playlists - sequences
of sound bits to be played after each other. One can
preprogram a sequence of sounds and add to this
schedule or playlist while sound playback is running.
This allows to concatenate sounds without any gap
inbetween, because one doesn't need to stop/restart
between 'FillBuffer' calls.

There is still only one soundbuffer available. In the
next driver release i will add support for multiple buffers,
but you can already define different sound chunks
in that one single buffer and then use schedules to
define subsegments or loops inside that buffer to
create different sounds, so you can get the effect
of multiple buffers with a bit more awkward programming.

Unfortunately this all lacks a good demo to
show it off in a meaningful and easy to understand
way. If you happen to have/write one, that would be
great.

-mario

--- In psychtoolbox@yahoogroups.com, "e_flister" <e_flister@...> wrote:
>
> > 1) i can't get 'stop' to return any faster than 10ms
>
> apologies -- it's under 1ms on my setup with an asio card. but not on
> osx... (forgot to mention i *am* setting waitForEndOfPlayback to 2)
>
> > 2) under windows with the enhanced dll, even on the setup with the
> > native asio card, i can't get more than one pahandle open, no matter
> > what the reqlatencyclass. on osx and under windows with the
> > unenhanced dll i can open around 9. any chance of allowing this under
> > the enhanced dll?
>
> i looked through the code here:
>
http://svn.berlios.de/wsvn/osxptb/beta/PsychSourceGL/Source/Common/PsychPortAudio
/PsychPortAudio.c
>
> and see that you have:
> #define MAX_PSYCH_AUDIO_DEVS 10
>
> this is what causes the limit under the non-enhanced dll. 10 is
> enough for my current application, i am just curious why a fixed limit
> is necessary?
>
> in the enhanced case, the Pa_OpenStream call is apparently returning
> paDeviceUnavailable.
>
> i looked into the portaudio code, and in pa_asio.cpp in OpenStream()
> it notes:
> /* unless we move to using lower level ASIO calls, we can only
> have one device open at a time */
>
> it's too bad, cuz it's nice to have multiple different sounds
> 'fillbuffered' up and ready to 'start' with as little latency as
> possible...
> -e
>