Closed kevinstadler closed 1 year ago
When the PortAudio dlls and jportaudio.jar are bundled with the library, JSyn will automatically use the JPortAudioDevice as long as
System.loadLibrary("portaudio_x64");
is called before instantiating the AudioDeviceManager
.
Since the PortAudio support is still considered experimental, it should probably not become the default mode for Windows, but only be loaded when:
Synthesizer
pointing to the device it throws a LineUnavailableException
, which is a clear indicator that PortAudio should be loaded, after which it shows the correct number of channels. (It might be necessary to create a new Synthesizer
for the JPortAudioDevice
to take come into action.)cfb0a1b also prepared the option of including PortAudio libraries for Mac, since JavaSound can sometimes negatively affect the sound output quality when using Bluetooth devices.
Closing this, with many thanks to @trackme518 for testing and support!
Many audio interfaces currently throw a
javax.sound.sampled.LineUnavailableException: line with format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian not supported
on Windows because 16 bit resolution is hard-coded in JSyn'sJavaSoundAudioDevice
(or don't list any audio devices to begin with, such as the Motu Ultralite mk5).This might be fixable by bundling the JPortAudio bindings for Windows and making use of the
JPortAudioDevice
instead.Work-in-progress
It turns out that getting (and) keeping the engine and synth in a valid state between device manager/synth switches is actually quite tricky. It goes something like this:
[x] when the
Engine
singleton is first instantiated it should silently create a synth on:PortAudioDeviceManager
if the first call to it isMultiChannel.usePortAudio()
(need to make it clear in the documentation that this absolutely needs to be the first Sound command in the sketch)JavaSoundDeviceManager
otherwise[x] it should then try to start the synth on:
Sound.outputDevice(...)
, the given output deviceAssuming we are on JavaSound:
PortAudioDeviceManager
and start a synth on its (possibly more informative?) default output device insteadJavaSoundAudioDevice
suppresses the informativeLineUnavailableException
that indicates we need PortAudio as well as clogging up the console (https://github.com/philburk/jsyn/blob/06f9a9a4d6aa4ddabde81f77878826a62e5d79ab/src/main/java/com/jsyn/devices/javasound/JavaSoundAudioDevice.java#L176-L185), so the Sound library needs to do low-level probing itself (note thatAudioSystem.isLineSupported(info)
does not seem to be very informative, the proof of the pudding lies in opening the line and provoking an exception) https://github.com/processing/processing-sound/blob/835fb831cf779def87b01028b3c44e9fe0d84ef2/src/processing/sound/Engine.java#L257After this first (silent) startup, there is a running
SynthesisEngine
with volume and output nodes.Whenever the user selects a different input or output device, do the following:
[x] if we're still on JavaSound: try to switch to PortAudio and, if successful, find the input and output devices with the same or similar names (this might need several attempts, again MME...), printing a note about changed device id's/names ultimately selected. This should also happen if
Sound.outputDevice()
was the first call to the library!SynthesisEngine
and all of its associated nodes. Check the Engine'splayingUnits
tracker for anything already instantiated and warn the user about it!AudioDeviceManagerFactory
only ever returns whichever device manager it instantiated first[x] if we're already on PortAudio: restart the synth on whatever devices given (as long as they have appropriate channels)
[x] an open question is who/where should execute
System.loadLibrary()
for the appropriate native libraries. When theJPortAudioDevice
is first instantiated it runs this static import block, not sure how it would raise a failure https://github.com/philburk/portaudio-java/blob/2ec5cc47d6f8abe85ddb09c34e69342bfe72c60b/src/main/java/com/portaudio/PortAudio.java#L101-L121 either waySystem.out
would need to be diverted as this is happening, to suppress JPortAudio output in the console, like so: https://github.com/processing/processing-sound/blob/835fb831cf779def87b01028b3c44e9fe0d84ef2/src/processing/sound/Engine.java#L37-L48[x] including (completely optional) PortAudio support on Mac might be desirable, e.g. when using some Bluetooth devices with strange line constraints (such as the Sony WH-CH510) with JavaSound the entire system audio seems to be forced into a low fidelity 16 bit mode, with the Processing audio output reminiscent of what is described here: https://www.reddit.com/r/processing/comments/qtgb1q/audio_quality_is_slow_buzzy_and_distorted/
Two outstanding glitches/corner cases:
"-1, possibly no available default device"
exceptionselectOutputDevice()
also automatically switches to PortAudio as expected when called with a device id that (erroneously) shows 0 output channels on JavaSound: https://github.com/processing/processing-sound/blob/843cacf7e10b7ca6267542ffa5eeae2044c7c87a/src/processing/sound/Engine.java#L379-L384