Hi,
here's a question that has been bugging me for quite a while: Why do we keep all those individual audio backends instead of just using portaudio everywhere? Are there any other reasons *besides* backwards compatibility with existing setups (saved preferences)?
Currently we have the following backend (excluding the dummy backends):
ALSA: s_audio_alsa.c
ESD: s_audio_esd.c
Jack: s_audio_jack.c
MMIO: s_audio_mmio.c
OSS: s_audio_oss.c
portaudio: s_audio_pa.c
---
Portaudio already supports all relevant audio backends (https://github.com/PortAudio/portaudio/tree/master/src/hostapi), so I don't see why we would have to provide our own implementations at all. It is just a big maintainance cost. Everytime we change something in the scheduling code, we have to make sure not to break any of those custom backends. Another advantage of using the portaudio "backend" is that you can always choose between the callback scheduler and the polling scheduler.
I acknowledge that removing backends could break existing setups (because of saved audio preferences). Alternatively, we might actually keep them around for some time but hide them from the GUI. Either way, we could post a warning whenever we encounter an "audioapi" value other than "API_PORTAUDIO" in the preferences or any of the "-alsa", "-mmio", "-jack", "-oss" command line flags. So in practice people would just need to go to the audio settings, select the device again and save it.
---
As a first step, we might compare our backend implementations with the portaudio implementations and see if there are any shortcomings.
Regarding MMIO: the portaudio implementation works fine (tested with 1024 buffer size + 20 ms latency, both with and without "callbacks"). Generally, MMIO is very outdated and shouldn't be used in the first place. On Windows 7 and above, the best choice - besides ASIO - would be WASAPI.
ESD (https://en.wikipedia.org/wiki/Enlightened_Sound_Daemon) is obsolete and can probably removed. Quote from "s_stuff.h": /*noideawhatthiswas,probablygonenow*/
This would only leave us with ALSA, Jack and OSS. To make comparisons, we would need to compile portaudio with ALSA, Jack and OSS support. Note that our portaudio folder doesn't include the "oss" and "jack" source folders.
---
BTW, portaudio is now officially hosted on GitHub (https://github.com/PortAudio/portaudio) and development seems pretty active. In April 2021 they have finally released a new version (0.19.7) after 5 years! There is even a recent PR for pulseaudio support: https://github.com/PortAudio/portaudio/pull/336.
This leads me to another question: should we include portaudio as a submodule? This would make it much easier to get the latest changes from upstream or send our own changes to upstream.
Christof
i'll start answering before reading your entire message, so...
On 1/21/22 02:58, Christof Ressi wrote:
Hi,
here's a question that has been bugging me for quite a while: Why do we keep all those individual audio backends instead of just using portaudio everywhere? Are there any other reasons *besides* backwards compatibility with existing setups (saved preferences)?
Currently we have the following backend (excluding the dummy backends):
ALSA: s_audio_alsa.c
ESD: s_audio_esd.c
minor side-note: ESD is just a dummy. the Enlightened Sound Daemon died some decade ago. i'm not sure the Pd backend was ever used.
it should be removed.
Jack: s_audio_jack.c
MMIO: s_audio_mmio.c
OSS: s_audio_oss.c
portaudio: s_audio_pa.c
Portaudio already supports all relevant audio backends
i never use portaudio, as it never really *worked* for me. and JACK always worked for me. i see little merit in abandoning a working system in favour of fixing a non-working system.
more importantly: i'm using JACK as the main audio provider for my system. so the relevant part for me is how portaudio deals with JACK.
and here the trouble starts. to name but the first that come to my mind:
- in the JACK-graph, Pd now shows up as "PortAudio". audacity shows up as "PortAudio-71". unless of course i start audacity first, in which case audacity gets the name "PortAudio" and Pd gets the name "PortAudio-67". (the numeric ID's are obviously generated (probably by JACK itself) to make the names unique). thank you very much. - when using JACK via PortAudio, i can pick a destination where i want to send audio to (and vice versa: a source to get audio from). that is: i can select my USB soundcard, or audacity (or whatever application uses the "PortAudio" name...), or... all from within Pd. while this sounds cool at first glance, it really isn't. it means that *all* my channels go to a single peer. but how do i do any non-trivial routing: e.g. [adc~ 1 2] go to my soundcard channels 17 & 18 (the headphones), while [adc~ 3 4] go to JackTrip and all four channels go to Ardour? i understand that PortAudio doesn't natively support setting up such routing, we have specialized software for that (qJackCtl, patchage,...). but PortAudio is actually counterproductive, as it insists on connecting to a peer - i cannot just pick "JACK - no automatic connection".
- oh, and while I *must* pick a peer, only peers that where available when i started Pd show up.
- finally, when i start Pd with PortAudio, i get a lot of output on the cmdline: ~~~ ALSA lib pcm.c:2664:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear ALSA lib pcm.c:2664:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe ALSA lib pcm.c:2664:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side ALSA lib pcm_route.c:877:(find_matching_chmap) Found no matching channel map ALSA lib pcm_route.c:877:(find_matching_chmap) Found no matching channel map ALSA lib pcm_route.c:877:(find_matching_chmap) Found no matching channel map ALSA lib pcm_route.c:877:(find_matching_chmap) Found no matching channel map ALSA lib pcm_a52.c:1001:(_snd_pcm_a52_open) a52 is only for playback ALSA lib confmisc.c:160:(snd_config_get_card) Invalid field card ALSA lib pcm_usb_stream.c:482:(_snd_pcm_usb_stream_open) Invalid card 'card' ALSA lib confmisc.c:160:(snd_config_get_card) Invalid field card ALSA lib pcm_usb_stream.c:482:(_snd_pcm_usb_stream_open) Invalid card 'card' ~~~
it seems that whatever these printouts mean to tell me is rather harmless, but even so it is a lot of noise that i would rather not see.
- finally when Pd *initializes* PortAudio i get one or more very nasty and loud click sounds (about 0dBFS). presumably this is because of some samplerate switching (but i really don't know).
so the question is: can we fix these problems within Pd? afaict the answer is "no". my reference PortAudio application is audacity, which shows exactly *all* of the problems described above.
for me this is really enough to not pick PortAudio. (esp. since the existing JACK backend does not have any of these problems). i guess most people do not hear the click sound when initializing PortAudio (it makes it unusable in any live performance context; and there are *some* applications that only offer PortAudio as a backend that i would think have widespread use). and probably many people do not care about the routing issues, because they only ever do trivial routing.
but for me, it's a no-go.
gmadrs IOhannes
Hi
I tend to side with IOhannes here. I find the flexibility of the current JACK backend with the options -nojackconnect, -jackname, -inchannels, -outchannels quite valuable. I don't know what portaudio offers in comparison, but one would expect a general purpose audio API covering a variety of audio backends cannot specialize in each them.
As IOhannes already mentioned, I find the aggressive probing annoying. Audacity, for instance, doesn't even show up in JACK unless it is playing. When the playing stops, it disappears again. That makes it unnecessarily complicated to use except for the most simple cases. I wouldn't want to have to reconnect Pd after each time I turn DSP off.
Maybe I'm suffering FUD and my concerns are unsubstantiated. But then again, why relying on portaudio not breaking things when the current JACK implementation seems quite mature now?
Roman
On Fri, 2022-01-21 at 08:49 +0100, IOhannes m zmoelnig wrote:
i'll start answering before reading your entire message, so...
On 1/21/22 02:58, Christof Ressi wrote:
Hi,
here's a question that has been bugging me for quite a while: Why do we keep all those individual audio backends instead of just using portaudio everywhere? Are there any other reasons *besides* backwards compatibility with existing setups (saved preferences)?
Currently we have the following backend (excluding the dummy backends):
ALSA: s_audio_alsa.c
ESD: s_audio_esd.c
minor side-note: ESD is just a dummy. the Enlightened Sound Daemon died some decade ago. i'm not sure the Pd backend was ever used.
it should be removed.
Jack: s_audio_jack.c
MMIO: s_audio_mmio.c
OSS: s_audio_oss.c
portaudio: s_audio_pa.c
Portaudio already supports all relevant audio backends
i never use portaudio, as it never really *worked* for me. and JACK always worked for me. i see little merit in abandoning a working system in favour of fixing a non-working system.
more importantly: i'm using JACK as the main audio provider for my system. so the relevant part for me is how portaudio deals with JACK.
and here the trouble starts. to name but the first that come to my mind:
- in the JACK-graph, Pd now shows up as "PortAudio".
audacity shows up as "PortAudio-71". unless of course i start audacity first, in which case audacity gets the name "PortAudio" and Pd gets the name "PortAudio-67". (the numeric ID's are obviously generated (probably by JACK itself) to make the names unique). thank you very much.
- when using JACK via PortAudio, i can pick a destination where i
want to send audio to (and vice versa: a source to get audio from). that is: i can select my USB soundcard, or audacity (or whatever application uses the "PortAudio" name...), or... all from within Pd. while this sounds cool at first glance, it really isn't. it means that *all* my channels go to a single peer. but how do i do any non-trivial routing: e.g. [adc~ 1 2] go to my soundcard channels 17 & 18 (the headphones), while [adc~ 3 4] go to JackTrip and all four channels go to Ardour? i understand that PortAudio doesn't natively support setting up such routing, we have specialized software for that (qJackCtl, patchage,...). but PortAudio is actually counterproductive, as it insists on connecting to a peer - i cannot just pick "JACK - no automatic connection".
- oh, and while I *must* pick a peer, only peers that where
available when i started Pd show up.
- finally, when i start Pd with PortAudio, i get a lot of output on
the cmdline:
ALSA lib pcm.c:2664:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear ALSA lib pcm.c:2664:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe ALSA lib pcm.c:2664:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side ALSA lib pcm_route.c:877:(find_matching_chmap) Found no matching channel map ALSA lib pcm_route.c:877:(find_matching_chmap) Found no matching channel map ALSA lib pcm_route.c:877:(find_matching_chmap) Found no matching channel map ALSA lib pcm_route.c:877:(find_matching_chmap) Found no matching channel map ALSA lib pcm_a52.c:1001:(_snd_pcm_a52_open) a52 is only for playback ALSA lib confmisc.c:160:(snd_config_get_card) Invalid field card ALSA lib pcm_usb_stream.c:482:(_snd_pcm_usb_stream_open) Invalid card 'card' ALSA lib confmisc.c:160:(snd_config_get_card) Invalid field card ALSA lib pcm_usb_stream.c:482:(_snd_pcm_usb_stream_open) Invalid card 'card'
it seems that whatever these printouts mean to tell me is rather harmless, but even so it is a lot of noise that i would rather not see.
- finally when Pd *initializes* PortAudio i get one or more very
nasty and loud click sounds (about 0dBFS). presumably this is because of some samplerate switching (but i really don't know).
so the question is: can we fix these problems within Pd? afaict the answer is "no". my reference PortAudio application is audacity, which shows exactly *all* of the problems described above.
for me this is really enough to not pick PortAudio. (esp. since the existing JACK backend does not have any of these problems). i guess most people do not hear the click sound when initializing PortAudio (it makes it unusable in any live performance context; and there are *some* applications that only offer PortAudio as a backend that i would think have widespread use). and probably many people do not care about the routing issues, because they only ever do trivial routing.
but for me, it's a no-go.
gmadrs IOhannes _______________________________________________ Pd-dev mailing list Pd-dev@lists.iem.at https://lists.puredata.info/listinfo/pd-dev
On 21.01.22 09:34, Roman Haefeli wrote:
As IOhannes already mentioned, I find the aggressive probing annoying. Audacity, for instance, doesn't even show up in JACK unless it is playing. When the playing stops, it disappears again. That makes it unnecessarily complicated to use except for the most simple cases. I wouldn't want to have to reconnect Pd after each time I turn DSP off.
Please add your voice here:
Thanks for your replies!
minor side-note: ESD is just a dummy. the Enlightened Sound Daemon died some decade ago. i'm not sure the Pd backend was ever used.
it should be removed.
Yes, this is what I got as well.
i never use portaudio, as it never really *worked* for me.
From what I read below, what you actually mean is: "I never use portaudio's Jack implementation because it is too limited for my use cases". I can't believe that portaudio never worked for you in general...
- in the JACK-graph, Pd now shows up as "PortAudio".
audacity shows up as "PortAudio-71". unless of course i start audacity first, in which case audacity gets the name "PortAudio" and Pd gets the name "PortAudio-67". (the numeric ID's are obviously generated (probably by JACK itself) to make the names unique). thank you very much.
portaudio already has a Jack-specific API to set the client name: https://github.com/PortAudio/portaudio/blob/master/include/pa_jack.h
- when using JACK via PortAudio, i can pick a destination where i want
to send audio to (and vice versa: a source to get audio from). that is: i can select my USB soundcard, or audacity (or whatever application uses the "PortAudio" name...), or... all from within Pd. while this sounds cool at first glance, it really isn't. it means that *all* my channels go to a single peer. but how do i do any non-trivial routing: e.g. [adc~ 1 2] go to my soundcard channels 17 & 18 (the headphones), while [adc~ 3 4] go to JackTrip and all four channels go to Ardour?
Is this possible with Pd's implementation? How do you do this?
i understand that PortAudio doesn't natively support setting up such routing, we have specialized software for that (qJackCtl, patchage,...). but PortAudio is actually counterproductive, as it insists on connecting to a peer - i cannot just pick "JACK - no automatic connection".
Please make a feature request: https://github.com/PortAudio/portaudio/issues
- oh, and while I *must* pick a peer, only peers that where available
when i started Pd show up.
Yes, it's a general problem with portaudio that you can't update the device list after calling Pa_Initialize(). There have been efforts to fix this (https://github.com/PortAudio/portaudio/tree/hotplug) but they seem to have lost momentum...
- finally, when i start Pd with PortAudio, i get a lot of output on
the cmdline:
That's also an issue with some ASIO drivers. At least with ALSA we should check
1) does this still happen with the latest portaudio version?
2) does portaudio offer a way to disable this?
3) can we add a way to disable this?
Another solution would be to temporarily disable console output (unless "sys_verbose" is set). In fact, this could also be nice on Windows.
- finally when Pd *initializes* PortAudio i get one or more very nasty
and loud click sounds (about 0dBFS). presumably this is because of some samplerate switching (but i really don't know).
I never had this problem...
1) Is this really a problem with portaudio itself, i.e. does it happen with several apps that use portaudio?
2) If yes, does it still happen with the latest version?
3) Does it only happen with certain backends?
If this is really a portaudio issue, consider reporting it: https://github.com/PortAudio/portaudio/issues
---
Actually, I wouldn't have a problem with keeping our Jack backend. The code is rather short, readable and serves a clear purpose (more flexibility). To be fair, SuperCollider and Supernova also have a dedicated Jack backend, probably for the same reasons.
(On the long run, however, it would be better to make a PR to portaudio to implement the missing features as extensions, instead of every app rolling their own implementation.)
Our MMIO backend doesn't have any advantage over the portaudio implementation. It is just technical debt and I would love to see it gone.
The ESD backend is obsolete and can be removed.
I'm not sure about ALSA. Here would should really compare and see if there's a real showstopper in the portaudio implementation (that cannot be easily patched).
What about OSS? I understand that it's legacy, so maybe we can just use the portaudio implementation?
---
Even if we decide to keep portaudio, Jack and ALSA, that would be 3 backends instead of 6! This would already be a big improvement.
To be clear: my concerns are really about maintainability and technical debt. For example, I regularly make experiments with the audio scheduling code. While I feel comfortable with the Jack and portaudio backend, I don't even dare to touch the other backends. Does anyone actually still understand all the code in s_audio_alsa.c, s_audio_alsamm.c, s_audio_mmio.c and s_audio_oss.c?
---
What about my proposition to include portaudio as a submodule, now that it's officially on GitHub?
Christof
On 1/21/22 14:59, Christof Ressi wrote:
i never use portaudio, as it never really *worked* for me.
From what I read below, what you actually mean is: "I never use portaudio's Jack implementation because it is too limited for my use cases". I can't believe that portaudio never worked for you in general...
i remember having problems (as in: dropouts). but this was years ago and because i had a running alternative (actually: two alternatives - JACK and ALSA) and so i had no incentive to spend time in improving my PortAudio experience.
portaudio already has a Jack-specific API to set the client name: https://github.com/PortAudio/portaudio/blob/master/include/pa_jack.h
probably. my reference application is still audacity which on my system does not set the JACK name (but then: i'm using audacity-2.4.2 which i understand is not the latest and greatest)
- when using JACK via PortAudio, i can pick a destination where i want
but how do i do any non-trivial routing: e.g. [adc~ 1 2] go to my soundcard channels 17 & 18 (the headphones), while [adc~ 3 4] go to JackTrip and all four channels go to Ardour?
Is this possible with Pd's implementation? How do you do this?
i'm using a dedicated JACK patching software (qjackctl). the point is that Pd's JACK implementation does not interfere with my patching software.
That's also an issue with some ASIO drivers. At least with ALSA we should check
does this still happen with the latest portaudio version?
does portaudio offer a way to disable this?
can we add a way to disable this?
Another solution would be to temporarily disable console output (unless "sys_verbose" is set). In fact, this could also be nice on Windows.
i think the proper way would be to have a flag to Pa_Initialize() to suppress such output (or even better: a callback) but that's of course something that needs to be changed in portaudio...
- finally when Pd *initializes* PortAudio i get one or more very nasty
and loud click sounds (about 0dBFS). presumably this is because of some samplerate switching (but i really don't know).
I never had this problem...
- Is this really a problem with portaudio itself, i.e. does it happen
with several apps that use portaudio?
as i said: i see all the problems i described also on audacity. this includes the click at initialisation.
- If yes, does it still happen with the latest version?
dunno.
- Does it only happen with certain backends?
it happens at initialization time. e.g. when i start "audacity". there are no problems when i turn on DSP (or in audacity: when i start playback)
fdcdsa IOhannes
it happens at initialization time. e.g. when i start "audacity". there are no problems when i turn on DSP (or in audacity: when i start playback)
That's interesting. I really never experienced/noticed this. If you have time, check if this still happens with the latest portaudio release and if yes, report it on GitHub!
On 21.01.22 18:00, IOhannes m zmölnig wrote:
my reference application is still audacity which on my system does not set the JACK name (but then: i'm using audacity-2.4.2 which i understand is not the latest and greatest)
I think Audacity should not be used as a reference application. Quoting Steve Daulton: "these issue[s} derive from an early design decision to open ports on demand and close them on stop (which was appropriate 20 years ago, but not today)."
On 1/21/22 14:59, Christof Ressi wrote:
I'm not sure about ALSA. Here would should really compare and see if there's a real showstopper in the portaudio implementation (that cannot be easily patched).
my understanding is that the native ALSA implementation allows for the lowest latencies (at least under Linux)
but: i really don't know how well portaudio behaves in this respect.
What about OSS? I understand that it's legacy, so maybe we can just use the portaudio implementation?
i think the merit of OSS is that it allows to build Pd with *zero* external dependencies and still have sound (and MIDI): no libalsa, no libjack.
this is probably also the most compelling reason for MMIO.
mgfds IOhannes
What about OSS? I understand that it's legacy, so maybe we can just use the portaudio implementation?
i think the merit of OSS is that it allows to build Pd with *zero* external dependencies and still have sound (and MIDI): no libalsa, no libjack.
this is probably also the most compelling reason for MMIO.
You can build portaudio with just OSS resp. MMIO support and get the same result :-)
(Not to mention that on Windows there are much better native options, like WASAPI.)
On 1/21/22 14:59, Christof Ressi wrote:
What about my proposition to include portaudio as a submodule
in general i do not like git submodules.
first of all they make problems when using 'git archive' to generate a source tarball (e.g. when you create a 'git tag', GitHub offers you a "Source Code" download which is created with this method). this is often a problem for downstream packagers (e.g. for the Debian packages) where crucial parts are missing from the source tarballs. in the specific case of portaudio i donÄt really mind, as in Debian we are using the system-provided PortAudio (and explicitely do *not* use the vendored version).
2nd, submodules do not allow for patching the vendored sources (e.g. we *could* remove the annoying printout at Pa_Initialize() in our vendored copy, but not with 'git submodule'). otoh, we haven't really used this in the past, so we probably don't need this anyhow.
so i really do not care. what i do care about is that the portaudio backend implementation of Pd remains (API-)compatible with released stable versions of PortAudio (and ideally (API-)compatible with the version of portaudio shipped in major linux distributions, esp. Debian)
now that it's officially on GitHub?
this i don't really understand. what makes GitHub different from BitBucket, GitLab, SourceForge or git.jackaudio.org with respect to 'git submodule's?
fgmdsa IOhannes
2nd, submodules do not allow for patching the vendored sources (e.g. we *could* remove the annoying printout at Pa_Initialize() in our vendored copy, but not with 'git submodule').
Actually, you can commit changes to a submodule: https://stackoverflow.com/a/5542964/6063908. However, it's probably cleaner to just make a fork.
what i do care about is that the portaudio backend implementation of Pd remains (API-)compatible with released stable versions of PortAudio (and ideally (API-)compatible with the version of portaudio shipped in major linux distributions, esp. Debian)
Good point! The existing API won't change, but we can't use *new* API functions.
now that it's officially on GitHub?
this i don't really understand. what makes GitHub different from BitBucket, GitLab, SourceForge or git.jackaudio.org with respect to 'git submodule's?
Ah, sorry. What I meant was: "now that PortAudio uses Git (instead of SVN)". However, I just realized that they "already" switched to Git in 2016, before they moved the repo to GitHub.
On 1/21/22 22:26, Christof Ressi wrote:
2nd, submodules do not allow for patching the vendored sources (e.g. we *could* remove the annoying printout at Pa_Initialize() in our vendored copy, but not with 'git submodule').
Actually, you can commit changes to a submodule: https://stackoverflow.com/a/5542964/6063908.
no you can't. or: you can (because a submodule is just another local repository), but you cannot push (unless you have write access to the upstream repository, e.g. https://github.com/PortAudio/portaudio)
However, it's probably cleaner to just make a fork.
then you can obviously use the forked repo to push to.
my point was that you cannot patch the code in the submodule and carry the changeset in the parent repository (that is: in the pure-data repository)
as antoine has written, you can do that with "git subtree" (which i do suggest in the pd-lib-builder docs), but there you include the full release history of the vendored project.
dgfs IOhannes