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

[scsynth portaudio] allow independent input output devices #4475

Conversation

dyfer
Copy link
Member

@dyfer dyfer commented Jul 7, 2019

Purpose and Motivation

This is a cleaned up version of #4009 focused on scsynth and documentation. See #4476 for supernova-related PR. Fixes #3990.

On Windows, scsynth was not able to select separate input and output devices (it accepted only single device name and tried to use it as both input and output). This essentially prevented manual device selection for anything other than soundcards with ASIO drivers.

This PR allows independent device selection, provides documentation and improves automatic device selection with PortAudio.

Thanks to @jamshark70 @sonoro1234 and others who helped with the original PR. This is the summary of the discussion so far:

  • the documentation was reviewed and seemed to be received favorably
  • there has been a lot of back and forth w/r/t which API to use for selecting the default device
    • there seemed to be a consensus that ASIO should be selected by default
    • if ASIO device is not available,
    • MME device is selected by default
      • this is the same behavior as before - more testing showed that sometimes non-working ASIO drivers are present on Windows system by default preventing server to boot
  • there have been multiple tests done and booting the server is now much more reliable than before
  • an issue of device names with unicode characters has been raised; this PR does not address that (see below)

Types of changes

  • Bug fix: allow scsynth with PortAudio backend to select separate input and output devices
  • New feature Bug fix: improve default device selection
    • if one device is specified, select another one from the same API
    • if no devices are specified, try selecting an ASIO device first
    • if no devices are specified, select a MME device (as before)
    • provide more verbose output for all choices made
    • provide better error reporting, including e.g. catching mismatched sample rate between input and output devices
  • Bug fix: treat empty strings as "invalid device" (triggering default device selection); previously empty string was causing scsynth to choose the last device on the list.
  • Bug fix: remove hardcoded default sample rate 44100 on scsynth with PortAudio on Windows (it will boot to hardware's sample rate by default)
    • this resolves booting when the API doesn't allow changing SR and SR was not specified on the command line
    • ASIO still boots to 44100 by default, which seems to be "by design" in PortAudio
  • Documentation: Provide new document describing audio device selection, including overview of different APIs on Windows

To-do list

  • Code is tested
  • All tests are passing
  • Updated documentation
  • This PR is ready for review
  • commit history cleanup (to be done after the review and before merging)

Unresolved issues

This PR does not solve setting device names for devices with unicode characters. Character encoding seems to be a larger issue. My work so far on it was moved to #4479. Partial names however are matched as before.

@sonoro1234
Copy link
Contributor

Default selection working for ASIO and MME
-o 0 and -i 0 works
Not matching samplerates works but there is a crash after could not initialize audio
(I think not related to this PR as also happens when hitting Ctrl+C)

Requested devices:
  In (matching device found):
  - Windows WASAPI : Mic interno (IDT High Definition Audio CODEC)
  Out (matching device found):
  - Windows WASAPI : Line 1/2 (4- M-Audio Fast Track Pro)


Requested devices Mic interno (IDT High Definition Audio CODEC) and Line 1/2 (4- M-Audio Fast Track Pro) use different sample
 rates. Please set matching sample rates in the Windows Sound Control Panel and try again.
SC_PortAudioDriver: PortAudio failed at Pa_OpenStream with error: 'Invalid sample rate'
could not initialize audio.

Now debugging crash

@dyfer
Copy link
Member Author

dyfer commented Jul 8, 2019

@sonoro1234 thanks, this also had the bug you found #4476 (comment) - fixed now.

@sonoro1234
Copy link
Contributor

Cant debug this because only happens with my WASAPI devices but I can reach them compiling with mingw

@dyfer
Copy link
Member Author

dyfer commented Jul 8, 2019

Could you give a full scsynth output for the WASAPI issue?

@sonoro1234
Copy link
Contributor

sonoro1234 commented Jul 8, 2019

It is not a WASAPI issue. The issue is a crash when not possible to boot.
I got one with ASIO and samplerate 11200

Requested sample rate 11200.000000 for devices Fast Track Pro ASIO and Fast Track Pro ASIO is not supported.
SC_PortAudioDriver: PortAudio failed at Pa_OpenStream with error: 'Invalid sample rate'
could not initialize audio.
[Thread 4388.0xa80 exited with code 1]
[Thread 4388.0x14ec exited with code 1]
[Thread 4388.0x16f0 exited with code 1]
[Thread 4388.0x17d0 exited with code 1]
[Thread 4388.0x13a4 exited with code 1]
[Thread 4388.0x14cc exited with code 1]
[Thread 4388.0xa58 exited with code 1]
terminate called without an active exception

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
[Inferior 1 (process 4388) exited with code 01]
(gdb) thread apply all bt
(gdb)

There is not information in gdb. I think that it is related to exception handling in scsynth.
May be in
https://github.com/supercollider/supercollider/blob/develop/server/scsynth/SC_World.cpp#L426
instead of return 0 an error should be thrown? @brianlheim

@dyfer
Copy link
Member Author

dyfer commented Jul 8, 2019

Are you requesting sample rate 11200? I've seen issues booting to SR < 44100 (like 8000) and I don't know what's the problem. Does this happen with the regular build as well?

@sonoro1234
Copy link
Contributor

sonoro1234 commented Jul 8, 2019

Are you requesting sample rate 11200? I've seen issues booting to SR < 44100 (like 8000) and I don't know what's the problem. Does this happen with the regular build as well?

This is not a problem, my ASIO card wont boot with 11200, I just asked for this impossible samplerate to debug the crash after could not initialize audio.
This crash has nothing related to your PR and everything is working as expected.

@dyfer
Copy link
Member Author

dyfer commented Jul 12, 2019

Note on selecting ASIO soundcard by default: I had an opportunity to do more tests on other systems. I found at least one other Windows laptop that had Realtek ASIO driver present (for the internal soundcard), and booting to this did not work.

Therefore, I removed selecting ASIO device by default.

This PR still adds more checks that help with device selection, but the default behavior (selecting default MME device) is the same as before.

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.

thanks @dyfer!!

server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
include/server/SC_WorldOptions.h Show resolved Hide resolved
HelpSource/Reference/AudioDeviceSelection.schelp Outdated Show resolved Hide resolved
server/scsynth/scsynth_main.cpp Show resolved Hide resolved
@dyfer
Copy link
Member Author

dyfer commented Jul 12, 2019

Thanks for the review @brianlheim ! I'll work on implementing changes.

Also, Travis CI is failing on an arithmetic unit test... not sure what's that about...

@mossheim
Copy link
Contributor

Thanks for the review @brianlheim ! I'll work on implementing changes.

Thanks! Let me know if you have any more questions or if any comments were unclear

Also, Travis CI is failing on an arithmetic unit test... not sure what's that about...

Not sure either, I just restarted the job. Don't worry about it.

@dyfer
Copy link
Member Author

dyfer commented Jul 12, 2019

Thanks! Let me know if you have any more questions or if any comments were unclear

Thanks! Things are rather clear, I'll just need a bit of time to work on this and will ask you if I have questions along the way.

@jrsurge jrsurge self-requested a review July 14, 2019 19:14
@dyfer
Copy link
Member Author

dyfer commented Jul 25, 2019

Hi @brianlheim, I tried to address your comments. Please let me know how this looks now.

Also, I created a function to get stream parameters to simplify some of the new code. Should I also use it in the DriverSetup section (which would be a work towards implementing your other suggestion) or should that be left for #4477?

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.

thanks marcin! this is not as comprehensive a review as i wanted to give right now but i think there should still be plenty to work with. i will try to respond to your other comments asap.

server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Show resolved Hide resolved
server/scsynth/SC_PortAudio.cpp Outdated Show resolved Hide resolved
@dyfer dyfer force-pushed the topic/scsynth-portaudio-input-output-devices branch from 1fee251 to fb991c5 Compare August 1, 2019 20:36
@dyfer
Copy link
Member Author

dyfer commented Aug 1, 2019

Thank you for your (partial?) review Brian!

I also have a question regarding IOType here.

Which is better:

bool isInput; //if matchingDeviceType is hypothetically neither Input nor Output, this stays unititialized
if (matchingDeviceType == IOType::Input)
    isInput = true;
else if (matchingDeviceType == IOType::Output)
    isInput = false;

if (isInput) {
    // do on input
} else {
    // do on output
}
fprintf(stdout, "this is %s\n", (isInput ? "input" : "output"));

vs

bool isInput = false; //we don't check whether it's IOType::Output or something else
if (matchingDeviceType == IOType::Input)
    isInput = true; 

if (isInput) {
    // do on input
} else {
    // do on output
}
fprintf(stdout, "this is %s\n", (isInput ? "input" : "output"));

vs

if (matchingDeviceType == IOType::Input) {
    // do on input
} else if (matchingDeviceType == IOType::Output) {
    // do on output
}
fprintf(stdout, "this is %s\n", ((matchingDeviceType == IOType::Input) ? "input" : "output")); //we don't check whether it's IOType::Output or something else

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.

OK, I took some more time to digest what was going on and I think this should be my last round of comments. Thanks again for your patience. When a comment is more a light recommendation than a request for changes, I've marked it with "(suggestion)" at the start.

Two general suggestions:

  • add documentation for functions (e.g., CheckPaDevices) in the header, not the cpp file.
  • I don't know if you need "Pa" in the name of every function since it's already obvious these functions operate on PortAudio streams and objects. I realize you may have been trying to follow precedent with GetPaDeviceFromName but for me it has the effect of making it harder to understand when a function call is to something in PortAudio's API vs part of the class interface.

To answer your earlier question:

Also, I created a function to get stream parameters to simplify some of the new code. Should I also use it in the DriverSetup section (which would be a work towards implementing your other suggestion) or should that be left for #4477?

Leave it for #4477 :)

I also have a question regarding IOType here.
Which is better:

I answered your question in an inline comment here

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

jrsurge commented Aug 4, 2019

Server crash with ASIO:

Thanks for spotting this!

If the user specifies a correct ASIO device, the server has to choose that device for both in and out, regardless of the default.

I tried correcting it. If only one device is specified, and it's a full duplex ASIO device, it will be used for both input and output. Could you test on your setup if the fix works correctly?

Thanks for the fix! This now works as expected

@dyfer
Copy link
Member Author

dyfer commented Aug 4, 2019

I found many minor grammar/style changes for the new Audio Device Selection helpfile. It was easier for me to change them myself, rather than adding dozens of review comments.

Thank you for the patches @jamshark70!

Question: you replaced "macOS" with "MacOS" in your patches. Are you sure this is best? It seems that Apple stylizes it "macOS" everywhere, including beginning of the sentence, and I was trying to follow that. Example:

Screen Shot 2019-08-04 at 12 20 51 PM

I don't have a very strong opinion, but I wanted to clarify my conscious choice here.

edit: after the dev meeting the consensus was that we should keep it as "macOS" in all cases. Thanks again for all the corrections!

@geoffroymontel
Copy link
Contributor

I've just tried the build with both my Steinberg MR816 ASIO card and Reaper's ReaRoute ASIO and both work well, no regression ! thanks !

@nhthn nhthn added this to the 3.10.3 milestone Aug 4, 2019
@dyfer
Copy link
Member Author

dyfer commented Aug 4, 2019

Thanks for testing @geoffroymontel
If I could ask you to test one more thing - what happens if you don't specify sample rate in server options and boot to ASIO? The server should boot to the device's SR, is that the case? Is it different from the previous behavior?

@jamshark70
Copy link
Contributor

Question: you replaced "macOS" with "MacOS" in your patches. Are you sure this is best? It seems that Apple stylizes it "macOS" everywhere, including beginning of the sentence, and I was trying to follow that.

No objection to changing it back to Apple/apple(?) style.

@geoffroymontel
Copy link
Contributor

If I could ask you to test one more thing - what happens if you don't specify sample rate in server options and boot to ASIO? The server should boot to the device's SR, is that the case? Is it different from the previous behavior?

I've tried the following

  • setting the MR816 to 96 khz
  • starting SC with s.options.device = "ASIO : Yamaha Steinberg FW ASIO";
  • SC would change the MR816 back to 44khz
Booting with:
  In: ASIO : Yamaha Steinberg FW ASIO
  Out: ASIO : Yamaha Steinberg FW ASIO
SCDoc: Indexed 1991 documents in 1.33 seconds
  Sample rate: 44100.000
  Latency (in/out): 0.004 / 0.012 sec
SC_AudioDriver: sample rate = 44100.000000, driver's block size = 64

The behaviour is the same on 3.10.2 on my Windows box

@dyfer
Copy link
Member Author

dyfer commented Aug 5, 2019

@geoffroymontel thanks for testing. I'll check if there's a reason. Otherwise at least it's not a regression.

@dyfer
Copy link
Member Author

dyfer commented Aug 5, 2019

update on ASIO default sample rate:

It seems this is a PortAudio bug. PortAudio obtains defaultSampleRate by checking whether the device supports a given SR agains a list of known SRs and takes the first match. I have tried to replace that code with

ASIOError asioError = ASIOGetSampleRate(&deviceInfo->defaultSampleRate);

and that seemed to work (server booted to device's sample rate), but I don't know enough to propose a full fix in PA for that. I have posted to their list so maybe it will be fixed upstream at some point.

edit:
It seems that PortAudio has a different understanding of what the "default sample rate" is than what I assumed. It seems that the current behavior is not likely to change:
https://lists.columbia.edu/pipermail/portaudio/2019-August/001893.html

@dyfer
Copy link
Member Author

dyfer commented Aug 9, 2019

@brianlheim please let me know when you think this is ready for me to rebase.

@jamshark70 could you take a look whether your comments were properly addressed?

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.

Thanks for your work on this and patience @dyfer .

@jamshark70 please review when you have time

@dyfer dyfer force-pushed the topic/scsynth-portaudio-input-output-devices branch from 8ee9913 to b315166 Compare August 10, 2019 22:28
dyfer added 2 commits August 10, 2019 15:30
Windows/Linux: list/use APIs in device names
Improve device selection logic
Windows: use device's sample rate by default
create new reference: AudioDeviceSelection.schelp
update and move Aggregate Device creation (macOS) to the new document
link the new document from other help files
@dyfer dyfer force-pushed the topic/scsynth-portaudio-input-output-devices branch from b315166 to 0316193 Compare August 10, 2019 22:30
@dyfer
Copy link
Member Author

dyfer commented Aug 10, 2019

This PR's commit history is now cleaned up (I rebased and squashed relevant commits).

Pending @jamshark70 's approval w/r/t #4475 (comment) it is ready to merge.

@mossheim
Copy link
Contributor

@jamshark70 no pressure but FYI this PR (and your approval of it) is what's currently blocking the 3.10.3 release.

@jamshark70 jamshark70 merged commit 906b219 into supercollider:3.10 Aug 15, 2019
@jamshark70
Copy link
Contributor

Sorry for the delay -- I hadn't realized that I was holding up a release.

I took the liberty of merging -- I hope that wasn't out of turn, but I recall this PR has already been extensively, exhaustively reviewed and if my approval was the last thing needed, seemed appropriate.

Much-needed feature!

@nhthn
Copy link
Contributor

nhthn commented Aug 16, 2019

thanks @jamshark70 !!!

@sonoro1234
Copy link
Contributor

@dyfer Congratulations for such a long work!!
supernova version should be done to have compatible command line and behaviour!!!

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.

7 participants