Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[portaudio:macos] avoid resampling when talking to audio hardware #4477

Merged

Conversation

dyfer
Copy link
Member

@dyfer dyfer commented Jul 7, 2019

Purpose and Motivation

In the process of working on #4009, I discovered CoreAudio-specific flags in PortAudio, that make it run on macOS with settings tuned for pro-audio applications. What it means in practice is that now PortAudio will ask the audio device to run at the requested sample rate, instead of allowing CoreAudio to resample. This matches scsynth's behavior with the native CoreAudio driver.

By default it will only benefit supernova on macOS (which uses PortAudio), however it is possible to build scsynth with PortAudio as well. so the changes were applied for both scsynth and supernova. The changes are applied to a common file that can be used by both scsynth and supernova.

EDIT: this will be re-worked after #4614 is merged. This is ready for review.

Types of changes

  • New feature

To-do list

  • Code is tested
  • All tests are passing (audio is running)
  • This PR is ready for review

Copy link
Contributor

@mossheim mossheim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC lines 364-403 in the scsynth file are nearly equivalent to lines 152-191 in the supernova file; we should combine them. the only difference I see is supernova clips the requested input and output channels to the advertised max ins and outs of the device. it's probably better if both programs behave the same here; I would be in favor of removing that clipping behavior for supernova since it offers a good opportunity to catch user error -- this check can be performed earlier and be a hard failure with an appropriate log line now.

server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
@dyfer
Copy link
Member Author

dyfer commented Jul 13, 2019

IIUC lines 364-403 in the scsynth file are nearly equivalent to lines 152-191 in the supernova file; we should combine them. the only difference I see is supernova clips the requested input and output channels to the advertised max ins and outs of the device. it's probably better if both programs behave the same here; I would be in favor of removing that clipping behavior for supernova since it offers a good opportunity to catch user error -- this check can be performed earlier and be a hard failure with an appropriate log line now.

Scsynth seems to clip that as well in lines 347 and 357, right? For a moment I though that this was related to #4029 but alas, no.

Not sure what kind of user error you're referring to - user certainly can request larger number of channels than the hardware provides (on scsynth). The extraneous channels are just not routed to hardware. This is a very common use case AFAICT.

@mossheim
Copy link
Contributor

Scsynth seems to clip that as well in lines 347 and 357, right? For a moment I though that this was related to #4029 but alas, no.

Yes! Thanks for pointing that out.

Not sure what kind of user error you're referring to - user certainly can request larger number of channels than the hardware provides (on scsynth). The extraneous channels are just not routed to hardware. This is a very common use case AFAICT.

Ah okay, never mind then :)

@mossheim
Copy link
Contributor

Btw @dyfer I believe you can add labels to your PRs now, can you please make sure to do that going forward? Thanks :)

@dyfer
Copy link
Member Author

dyfer commented Jul 16, 2019

Btw @dyfer I believe you can add labels to your PRs now, can you please make sure to do that going forward? Thanks :)

Sure! Sorry, I haven't noticed I can do that now.

@dyfer
Copy link
Member Author

dyfer commented Jul 16, 2019

So to move forward with this, should I combine the section as outlined in the previous comment? Should that code go into an common header file?

@mossheim
Copy link
Contributor

So to move forward with this, should I combine the section as outlined in the previous comment? Should that code go into an common header file?

Yes please; common/ is a good folder for now I think? If we started combining more code between the server implementations I would want to think harder about where files like that should go. (server/common?)

@dyfer
Copy link
Member Author

dyfer commented Jul 16, 2019

Yes please; common/ is a good folder for now I think? If we started combining more code between the server implementations I would want to think harder about where files like that should go. (server/common?)

Hm, I see many things in common/ but some in include/server/... which one is better?

BTW isn't this a little messy ATM?

@mossheim
Copy link
Contributor

include is for the public facing API, this is internal so should go in common.

what exactly is messy? i probably agree, just don't know what "this" refers to ;)

@dyfer
Copy link
Member Author

dyfer commented Jul 16, 2019

include is for the public facing API, this is internal so should go in common.

Ah, makes sense. This makes it less messy :)

what exactly is messy? i probably agree, just don't know what "this" refers to ;)

It seems like common has things related mostly to sclang, but also some related to server, is that right? This is what I was mostly referring to.

@mossheim
Copy link
Contributor

It seems like common has things related mostly to sclang, but also some related to server, is that right? This is what I was mostly referring to.

i think so?

what's the status of this PR now? is it depending on anything else or is it ready for review?

@dyfer
Copy link
Member Author

dyfer commented Dec 24, 2019

@brianlheim this PR is relevant for PortAudio backend on macOS, which is by default used only by supernova, and not scsynth. However, supernova's PortAudio backend is not using this implementation yet, see #4476.
I would say that It is technically ready to review, but this code will only be used if one builds with PortAudio backend explicitly on macOS (which would make scsynth use PortAudio and thus test this PR). Whether this is used by scsynth or supernova should not make a difference for testing purposes, AFAIU.

@@ -156,6 +161,11 @@ PaStreamParameters MakePaStreamParameters(int device, int channelCount, double s
streamParams.channelCount = channelCount;
streamParams.sampleFormat = fmt;
streamParams.suggestedLatency = suggestedLatency;
#ifdef __APPLE__
PaMacCore_SetupStreamInfo(&macInfo, paMacCorePro);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really want this called on every invocation of this function?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not, but it doesn't seem to hurt it. Should this be changed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wondering. i'm a fan of keeping things as close to where they're used as possible. can you move macInfo inside this function as a static variable? then a reader doesn't need to jump up to the top of the file to find out what macInfo is.

Copy link
Member Author

@dyfer dyfer Dec 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it needs to be the same macInfo instance (for both times this function is called for input and output device), otherwise I was getting crashes. But I can investigate again...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static would make it the same variable across calls and persistent for the life of the application. if it were a non-static local variable, it would be deallocated after the function call and you would probably get a segmentation fault later from the dangling pointer you stored in streamParams

see https://stackoverflow.com/questions/5033627/static-variable-inside-of-a-function-in-c for a quick explanation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perfect! Thank you for that clarification, this is very helpful. I'll try this shortly.

@dyfer dyfer force-pushed the topic/portaudio-macos-avoid-resampling branch from ef2d618 to 7638b9e Compare December 27, 2019 19:52
@dyfer
Copy link
Member Author

dyfer commented Dec 27, 2019

@brianlheim how does it look now?

@mossheim mossheim merged commit 1fc363d into supercollider:develop Dec 27, 2019
@mossheim
Copy link
Contributor

good, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants