Ubuntu: ServerOptions.devices throws Primitive '_ListAudioDevices' failed

Hello all,
I’m new to this list, a SC user for 10+ years but on MacOS. Now I switched to Ubuntu 20.04, the install went well, but when I run: ServerOptions.devices, I get the error below. I do have sound from SC, so there definitely is an audio device (the internal audio). Not sure if that helps, but I added the booting messages at the bottom of this post.
I hope someone can point me in the right direction to solve this.
Thanks!
Robert

ERROR: Primitive '_ListAudioDevices' failed.
Failed.
RECEIVER:
class ServerOptions (0x55f3d90c7cc0) {
  instance variables [19]
    name : Symbol 'ServerOptions'
    nextclass : instance of Meta_ServerQuit (0x55f3d8c17580, size=19, set=5)
    superclass : Symbol 'Object'
    subclasses : nil
    methods : instance of Array (0x55f3d90c7e40, size=85, set=7)
    instVarNames : instance of SymbolArray (0x55f3d90c86c0, size=39, set=5)
    classVarNames : instance of SymbolArray (0x55f3d90c8dc0, size=1, set=2)
    iprototype : instance of Array (0x55f3d90c8940, size=39, set=6)
    cprototype : instance of Array (0x55f3d90c8e80, size=1, set=2)
    constNames : nil
    constValues : nil
    instanceFormat : Integer 0
    instanceFlags : Integer 0
    classIndex : Integer 179
    classFlags : Integer 0
    maxSubclassIndex : Integer 179
    filenameSymbol : Symbol '/usr/local/share/SuperCollider/SCClassLibrary/Common/Control/Server.sc'
    charPos : Integer 0
    classVarIndex : Integer 431
}
CALL STACK:
	MethodError:reportError
		arg this = <instance of PrimitiveFailedError>
	Nil:handleError
		arg this = nil
		arg error = <instance of PrimitiveFailedError>
	Thread:handleError
		arg this = <instance of Thread>
		arg error = <instance of PrimitiveFailedError>
	Object:throw
		arg this = <instance of PrimitiveFailedError>
	Object:primitiveFailed
		arg this = <instance of Meta_ServerOptions>
	Interpreter:interpretPrintCmdLine
		arg this = <instance of Interpreter>
		var res = nil
		var func = <instance of Function>
		var code = "ServerOptions.devices"
		var doc = nil
		var ideClass = <instance of Meta_ScIDE>
	Process:interpretPrintCmdLine
		arg this = <instance of Main>
^^ The preceding error dump is for ERROR: Primitive '_ListAudioDevices' failed.
Failed.
RECEIVER: ServerOptions
Booting server 'localhost' on address 127.0.0.1:57110.
Faust: supercollider.cpp: sc_api_version = 3
Faust: FaustGreyholeRaw numControls=7
Found 0 LADSPA plugins
Faust: supercollider.cpp: sc_api_version = 3
Faust: FaustJPverbRaw numControls=11
jackdmp 1.9.12
Copyright 2001-2005 Paul Davis and others.
Copyright 2004-2016 Grame.
Copyright 2016-2017 Filipe Coelho.
jackdmp comes with ABSOLUTELY NO WARRANTY
This is free software, and you are welcome to redistribute it
under certain conditions; see the file COPYING for details
JACK server starting in realtime mode with priority 10
self-connect-mode is "Don't restrict self connect requests"
audio_reservation_init
Acquire audio card Audio0
creating alsa driver ... hw:0|hw:0|1024|2|44100|0|0|nomon|swmeter|-|32bit
configuring for 44100Hz, period = 1024 frames (23.2 ms), buffer = 2 periods
ALSA: final selected sample format for capture: 32bit integer little-endian
ALSA: use 2 periods for capture
ALSA: final selected sample format for playback: 32bit integer little-endian
ALSA: use 2 periods for playback
JackDriver: client name is 'SuperCollider'
SC_AudioDriver: sample rate = 44100.000000, driver's block size = 1024
JackDriver: connected  system:capture_1 to SuperCollider:in_1
JackDriver: connected  system:capture_2 to SuperCollider:in_2
JackDriver: connected  SuperCollider:out_1 to system:playback_1
JackDriver: connected  SuperCollider:out_2 to system:playback_2
SuperCollider 3 server ready.
JackDriver: max output latency 46.4 ms
Requested notification messages from server 'localhost'
localhost: server process's maxLogins (1) matches with my options.
localhost: keeping clientID (0) as confirmed by server process.
Shared memory server interface initialized
1 Like

In linux you manage the devices with JACK, not from SuperCollider.

By default, SuperCollider on Linux uses JACK, and the audio device selection is managed by the JACK server. ServerOptions cannot override JACK's selection of audio hardware.

See Audio devices selection help page in the docs.

Hope that helps

1 Like

Another thing:

With supernova you need to start jack manually before booting the server.

With scsynth jack starts automatically.

1 Like

Thanks for the answers. I will take a look at some Jack documentation. I’ve used it before on Mac and was not very enthoustiastic about it. But I’ll give it another try (I guess I’ll have to :wink: )

This is a bug, no doubt. I get it too on Lubuntu 20 run in a VM with a develop-compiled SC tree. It does not impact operation otherwise.

Side note: when running SC in a VMware Linux VM you have to use “playback only” for the audio device in qjackctl, otherwise if you let it try to connect the inputs as well (“duplex” being the default), you do get no sound from SC, even if sound output works fine otherwise from the VM (e.g. Firefox on youtube).

No, it isn’t a bug. See the device selection help file. (Edit: The reasoning here is, because sclang can’t do anything to change JACK’s hardware device, there is no point in trying to determine which hardware devices are available. Also, no other JACK software tries to do that: Ardour in Linux has a dialog for JACK connections but not hardware; the “device selection” menu in Audacity chooses JACK source and target ports but not hardware. In SC, if you want to manage JACK connections programmatically, the LinuxExternal quark can help, but for fairly evident reasons that mechanism doesn’t apply to macOS or Windows. Lastly, most users set up JACK with the ALSA backend but other backends are available, so it would be inordinately complex to have sclang communicate directly with the audio backend to get a hardware device list.)

hjh

I’m saying it should return an empty list or something like that instead of throwing an error. It could also post a warning that devices aren’t selectable through Jack.

Older discussion I found

The Windows part was fixed with https://github.com/supercollider/supercollider/pull/4742 but obviously that kind of fix doesn’t apply to Linux.

Also of some note, supposedly you can have multiple audio devices in Jack, but the documentation on how anything can select them (through Jack) is rather poorly written

https://jackaudio.org/faq/multiple_devices.html

Mkay, apparently the only thing that’s actually possible and documented with Jack is combining multiple cards in one pseudocard. (And the official faq is apparently wrong even how to do that. Apparently the best way is use “zita” bridges.) But at least the number of in and out channels that jack makes available is probably not unbtainable from jack… Although the API for that is fairly poorly documented as well. Apparently you can ask if a port is “terminal” which in jack terminology means it’s connected to the hardware.

On VMware at least,

s.options.numOutputBusChannels // 2; true
s.options.numInputBusChannels // 2; totally false and bogus

vs

Acquire audio card Audio0
creating alsa driver ... hw:AudioPCI|-|1024|2|44100|0|0|nomon|swmeter|-|32bit
configuring for 44100Hz, period = 1024 frames (23.2 ms), buffer = 2 periods
ALSA: final selected sample format for playback: 16bit little-endian
ALSA: use 2 periods for playback
JackDriver: client name is 'SuperCollider'
SC_AudioDriver: sample rate = 44100.000000, driver's block size = 1024
JackDriver: connected  SuperCollider:out_1 to system:playback_1
JackDriver: connected  SuperCollider:out_2 to system:playback_2
SuperCollider 3 server ready.

(There are no actual inputs connected.)

I second that this is not a bug.
Currently, if you wanted to test whether you are able to list/select devices on a given system (in our case - whether it uses JACK or not), you could use
try { } { }

If this method did not return an error, you wouldn’t know (programmatically) that it had failed.
I agree that the error message could be made more specific though.

Marcin

Expanding on Marcin’s comment:

When something goes wrong like this, the options (IMO in decreasing order of preference):

  • Throw a descriptive error – so either you catch the error and handle it, or get a human-friendly message in the post window.

  • Allow the method internals to fail and (probably) throw an error. It’s possible to catch and handle, but harder to identify the specific scenario. Printed error output is harder for users to understand. That’s the current situation here.

  • Return some sentinel value to indicate failure. Now user code is obligated to check for that result – if it doesn’t, it’s likely to fail later with an obscure error whose relationship to the real cause is less than obvious. (This is already mildly annoying with File, where you have to check isOpen before proceeding, and SoundFile, where openRead returns nil if it can’t access the path :dizzy_face: … it would be more consistent if they both threw easily recognizable errors instead of having different interfaces.)

  • Return an object of the expected type but with empty or otherwise null contents – effectively, silent failure. (SC is tending to move away from silent failure as an exception handling strategy. I think that’s a correct move.)

We could improve this situation, as Marcin says, by improving the explanation in the exception being thrown. Other options IMO would be a step backward.

hjh

How is the code written in sclang (i.e. SC “user code”) supposed to find (on Linux) out how many outs (or ins) the jackaudio has configured?

Currently with the LinuxExternal quark, you can find the input or output ports matching the pattern you’re interested in – hardware is usually “system:capture” and “system:playback” with multiple instances of each, numbered.

I think it’s more typical that users know in advance how many channels they need for a given application, and configure both JACK and their code accordingly. Isn’t it? Even in a DAW – I’m pretty sure you can set up a 5.1 surround project even if your soundcard has only two channels.

hjh

How is the code written in sclang (i.e. SC “user code”) supposed to find (on Linux) out how many outs (or ins) the jackaudio has configured?

I’m not sure if I understand.

Currently we have no way of knowing how many channels the audio device has on any platform (IMO this is a deficiency, but maybe at some point we’ll get to implementing this).

If this comment refers to the number of channels between SC and JACK itself - then this is set with s.options.num(In/Out)putBusChannels - the servers will boot exposing the requested number of channels to the JACK server. It’s the server’s responsibility to map these to hardware channels - usually it will connect first “n” channels to hardware, where “n” is the number of channels provided the hardware provides.

BTW when using JACK on macOS or Windows then one uses JackRouter “between” SC and JACK, which is a virtual device with a set number of channels. This is not the case on linux, where we connect to JACK directly and SC defines how many channels are exposed to JACK.

m