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

supernova: enable building JACK API on macOS #4291

Merged
merged 3 commits into from May 3, 2020

Conversation

dyfer
Copy link
Member

@dyfer dyfer commented Feb 6, 2019

Purpose and Motivation

Currently supernova is hardcoded to use PortAudio on macOS. This PR modifies CMakeLists file to mimic the API choice in scsynth (with the exception of choosing portaudio instead of coreaudio by default on macOS).

Types of changes

  • Documentation
  • Bug fix (?)
  • New feature (?)

To-do list

  • Code is tested (except for Windows, as supernova doesn't build on Windows)
  • scsynth and supernova boot from the terminal using JACK backend
  • scsynth and supernova boot from sclang using JACK backend
  • supernova's CMakeLists logic is updated to mimic scsynth's CMakeLists
  • Updated documentation
  • Commit history is cleaned up and consolidated
  • This PR is ready for review

Comments

Previously I had a problem connecting to JACK server when the scsynth/supernova were booted from SC:

(details)

I am able to start servers from command line, and they connect to JACK backend and make sound. However, if I try booting server from SC, I'm getting

Booting server 'localhost' on address 127.0.0.1:57110.
Found 0 LADSPA plugins
Faust: supercollider.cpp: sc_api_version = 3
Faust: FaustJPverbRaw numControls=11
Faust: supercollider.cpp: sc_api_version = 3
Faust: FaustGreyholeRaw numControls=7
could not initialize audio.
Server 'localhost' exited with exit code 0.

for scsynth
and

Booting server 'localhost' on address 127.0.0.1:57110.
Supernova booting
Found 0 LADSPA plugins
Server 'localhost' exited with exit code 0.

for supernova.

Again, if I boot the server in terminal with the same options (taken from s.options.asOptionsString), it starts and works. I'd appreciate ideas how to debug this further...

I realized, that this was due to JACK (installed by homebrew in /usr/local/bin) not being in the $PATH in the SC environment.

Solution:

"PATH".setenv("echo $PATH".unixCmdGetStdOut ++ ":/usr/local/bin"); //add to $PATH

And also make the scsynth/supernova automatically connect to system inputs/outputs:

// connect all input channels with system
"SC_JACK_DEFAULT_INPUTS".setenv("system");
// connect all output channels with system
"SC_JACK_DEFAULT_OUTPUTS".setenv("system");

After that, I was able to start scsynth/supernova and connect it to (previously started) jack server.

Caveats:

  • jackd seems to require a single device for input and output, so in order to use it with the internal soundcard on a mac, one needs to create an aggregate device
  • I have an intermittent problem with the inputs (in jack itself) not having any signal present; can't find a reliable reproducer though, this seems to be an issue with the jack itself and there seems to be an open issue about it: Please verify if CoreAudio works with sample rates different from 44.1k  jackaudio/jack1#65

I was able to start jack either from terminal, qjackctl gui, or with SC:

~jackPid = "jackd -d coreaudio -r48000 -p512".unixCmd;

JACK was installed with

brew install jack

and

brew install qjackctl

for the GUI allowing control over JACK connections.

For reference: what sparked this PR is a problem I discovered with JackOSX.

edit:
I tested this with both jack1 from homebrew and jack2 from JackOSX.0.92_b3. Compilation works in both cases (with some problem in the verification stage for jack2).

The takeaway is that both JACKs seem to be a little broken:

  • jack1 has intermittent problems with audio in
  • jack2 with JackRouter does not clean up resources when exiting, so the coreaudiod process is left with ~150MB of garbage memory (?) after each start/stop of jack server

@mtmccrea
Copy link
Member

mtmccrea commented Feb 12, 2019

[ ] Updated documentation (does this need documentation?)

All of your observations about installation, caveats, and starting jack by various means seem worth documenting. I could see this in either a new section of README_MACOS.md or its own "Jack on macOS" wiki or .md

@dyfer
Copy link
Member Author

dyfer commented Feb 12, 2019

I added documentation for building and running SC with JACK on macOS.

For the sake of completeness, I also tested with JackOSX (which is jack2, as opposed to jack1 from homebrew). The build process mostly worked, SC starts and I can make sound using SC<->JACK, however, when building, the verify_app stage failed:

-- Verifying app
-- ===========================================================================
-- Analyzing app='/somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app'
-- bundle='/somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app'
-- executable='/somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/MacOS/SuperCollider'
-- valid='1'
-- executable file 1: /somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/Frameworks/QtWebEngineCore.framework/Versions/5/Helpers/QtWebEngineProcess.app/Contents/MacOS/QtWebEngineProcess
-- executable file 2: /somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/MacOS/sclang
-- executable file 3: /somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/MacOS/SuperCollider
-- executable file 4: /somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/Resources/scsynth
-- executable file 5: /somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/Resources/supernova
-- verified='0'
-- info='external prerequisites found:
f='/somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/MacOS/sclang'
external_prereqs='/Library/Frameworks/Jackmp.framework/Versions/A/Jackmp'
;external prerequisites found:
f='/somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/Resources/scsynth'
external_prereqs='/Library/Frameworks/Jackmp.framework/Versions/A/Jackmp'
;external prerequisites found:
f='/somePath/src/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/Resources/supernova'
external_prereqs='/Library/Frameworks/Jackmp.framework/Versions/A/Jackmp'
'
--
CMake Error at /usr/local/Cellar/cmake/3.13.3/share/cmake/Modules/BundleUtilities.cmake:1137 (message):
  error: verify_app failed
Call Stack (most recent call first):
  editors/sc-ide/cmake_install.cmake:96 (verify_app)
  editors/cmake_install.cmake:37 (include)
  cmake_install.cmake:55 (include)


make: *** [install_buildpart_0] Error 1

** BUILD FAILED **


The following build commands failed:
	PhaseScriptExecution CMake\ PostBuild\ Rules build/SuperCollider.build/RelWithDebInfo/install.build/Script-89009FFBE94745E286AE1E35.sh
(1 failure)

Jack libraries are present (symlinked) at /Library/Frameworks/Jackmp.framework/Versions/A/Jackmp. I don't understand libraries linking (...) so I'm not sure if this is useful, but supernova (as well as scsynth) do point to that library:

myName$ otool -L Install/SuperCollider/SuperCollider.app/Contents/Resources/supernova
Install/SuperCollider/SuperCollider.app/Contents/Resources/supernova:
...
	/Library/Frameworks/Jackmp.framework/Versions/A/Jackmp (compatibility version 1.0.0, current version 1.0.0)
...

For comparison, when building against jack from homebrew, libjack.0.dylib is copied to /SuperCollider.app/Contents/Frameworks and otool shows

myName$ otool -L SuperCollider.app/Contents/Resources/supernova
SuperCollider.app/Contents/Resources/supernova:
...
	@loader_path/../Frameworks/libjack.0.dylib (compatibility version 1.0.0, current version 1.28.0)
...

I guess I need to install jackosx again and check where it has its libraries and why are they not copied. WIP...

Thinking more about it, the linking issue applies both to scsynth and supernova and is not related to the changes in this PR. I think that this is now ready for review.

Copy link

@beatboxchad beatboxchad left a comment

Choose a reason for hiding this comment

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

This looks good to me. I didn't test the build, because I'm not on MacOS.

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! one substantial thing, the rest are minor/style issues

README_MACOS.md Outdated
In order to build with JACK, you need to add the `-DAUDIOAPI=jack` flag to cmake. The full command to configure the build (with supernova) would be:

```
cmake -G Xcode -DCMAKE_PREFIX_PATH=`brew --prefix qt5` -DSUPERNOVA=ON -DAUDIOAPI=jack ..
Copy link
Contributor

Choose a reason for hiding this comment

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

would prefer to stay away from giving full commands, as it looks different for everyone depending on use case and ends up cluttering the readme. i think it's enough to say you would pass that as another option when you configure your build.

Copy link
Member Author

Choose a reason for hiding this comment

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

I included this since I personally like full commands I can just copy/paste - I know this is lazy, but I like to have that option. If you insist this is suboptimal, I'm happy to remove that.

My question is in what case on macOS the command would be different? If you have a custom place for QT you probably know enough to change it, and if not, this is helpful for newbies (which is what I was for quite some time as far as building goes)

Copy link
Contributor

Choose a reason for hiding this comment

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

there are over a dozen options you can pass to cmake to configure your supercollider build, some of them are documented in this very file.

i understand the desire to be beginner friendly but this really isn't that in my opinion, it's just creating clutter. let's teach people how to effectively use the build system if they don't know, rather than giving complete commands for every possible build scenario. if this command were universal or even the common case, you might have a point.

Copy link
Member Author

Choose a reason for hiding this comment

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

if this command were universal or even the common case, you might have a point.

IMO this was the common case for this particular scenario (building with JACK) but I see your point it might not be so I'll remove it.

README_MACOS.md Show resolved Hide resolved
README_MACOS.md Outdated
```
jackd -d coreaudio
//or
jackd -d coreaudio -r48000 -p512 //specifying sample rate and buffer size
Copy link
Contributor

Choose a reason for hiding this comment

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

most shells on macOS use # for comments

README_MACOS.md Outdated

Afterwards proceed with the build process as usual.

##### Running SuperCollider with JACK
Copy link
Contributor

Choose a reason for hiding this comment

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

should probably be only ### (same below)

Copy link
Member Author

@dyfer dyfer Jan 3, 2020

Choose a reason for hiding this comment

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

##### was intentional it's used elsewhere in this file as well, but if you prefer to have ### here that's fine.

README_MACOS.md Outdated Show resolved Hide resolved
server/supernova/CMakeLists.txt Outdated Show resolved Hide resolved
endif()
message(STATUS "Supernova audio API: ${AUDIOAPI}")

if (AUDIOAPI STREQUAL jack)
find_library(JACK NAMES jack)
Copy link
Contributor

Choose a reason for hiding this comment

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

is this necessary with find_package above? seems like the same work done twice in different ways. also dubious of just failing silently if jack isn't found here

endif()
message(STATUS "Supernova audio API: ${AUDIOAPI}")

if (AUDIOAPI STREQUAL jack)
Copy link
Contributor

Choose a reason for hiding this comment

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

change this and the portaudio check below from jack to "jack" -- otherwise, cmake will first see if a variable with the name jack exists, which is not what you want

Copy link
Member Author

Choose a reason for hiding this comment

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

this is taken from the scsynth CMakeLists:

if(AUDIOAPI STREQUAL jack)

should this be changed in scsynth's CMakeLists as well?

server/supernova/CMakeLists.txt Show resolved Hide resolved
find_library(JACK NAMES jack)
if (JACK)
target_compile_definitions(libsupernova PUBLIC JACK_BACKEND)
target_link_libraries(libsupernova ${JACK})
target_include_directories(libsupernova PUBLIC ${JACK_INCLUDE_DIRS})
endif()
elseif (AUDIOAPI STREQUAL portaudio)
target_include_directories(libsupernova PUBLIC ${PORTAUDIO_INCLUDE_DIRS})
if (WIN32)
Copy link
Contributor

Choose a reason for hiding this comment

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

remove spaces between if/elseif and paren throughout the code you added

@dyfer
Copy link
Member Author

dyfer commented Jan 3, 2020

@brianlheim I can't seem to respond to the comment pointing to code that has changed (?), here's more response regarding switching backend from coreaudio to portaudio in supernova:

if it's not supported, i think this should be a fatal error rather than defaulting to something the user may not want. perhaps we need a separate CMake option for supernova audio api?

I personally treat it as a temporary situation where we don't have coreaudio backend for supernova. If you feel strongly about it, I can change it to throw an error if coreaudio is explicitly requested. I think adding more granularity to cmake is not optimal, there's already a lot there... but if you think that's best then I can add that. I personally don't think having 2 servers with different backends is useful (unless necessary, as it is now on macOS), but again I'm happy to be persuaded about it.

…dio API selection

Modified CMakeLists.txt to make Supernova build with native JACK backend on OSX when specified JACK as audio API in cmake options.
@dyfer
Copy link
Member Author

dyfer commented Apr 13, 2020

I rebased this PR to include the latest changes from develop.

I also added an error message if the user explicitly requests coreaudio backend (previously in this PR a warning was shown and the selection was changed to portaudio). Currently I don't think that adding separate audio api switches for the two servers is beneficial (ideally we should have all APIs implemented in both).
This is the current audio API selection logic on macOS:

requested API scsynth supernova
default coreaudio portaudio
coreaudio coreaudio ERROR
portaudio portaudio portaudio
jack jack jack

abort cmake when not implemented coreaudio API is requested
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! this all looks good to me. i didn't respond to them individually, but your comments from the last round of review were all reasonable. sorry, i didn't realize you had cut-and-pasted that CMake config section.

@mossheim mossheim merged commit bdbfe24 into supercollider:develop May 3, 2020
@dyfer dyfer deleted the topic/jack_on_osx branch May 3, 2020 07:17
@dyfer dyfer mentioned this pull request May 3, 2020
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp: build CMake build system os: macOS
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants