philburk / jsyn

Modular audio synthesizer library with unit generators in Java
http://www.softsynth.com/jsyn
Apache License 2.0
223 stars 61 forks source link

Starting a Synthesizer with Port Audio and a device input count of greater then two crashes #89

Open lukasroberts opened 3 years ago

lukasroberts commented 3 years ago

When starting the synthesizer engine with a count of devices greater than two utilising the PortAudio bindings the library just crashes. It does work when just specifying the number of device inputs to two.

I am trying this on a Mac (10.15.6) with the JNIlibs properly linked.

Also to add the output from the logs of the JSyn lib: Audio input from Rane Seventy-Two Audio - Core Audio JPortAudio: 64-bit requestedFramesPerBuffer = 128, coreAudioBufferSizeFrames = 384 ringBufferSize after = 2048

^^ The above shows that it's initialising the device, and then allocating the ringBufferSize, however then it appears lower down in src/hostapi/coreaudio/pa_mac_core_blocking.c, it doesn't like that size as from initializeBlioRingBuffers it get's a SIGABRT

All I'm trying to achieve is getting specific inputs for two specific line ins for a soundcard (a bit like the DualOscilloscope example ) However, I'm having absolutely no luck.

Here is the output I'm getting as a general crash for the system:

System Integrity Protection: enabled Crashed Thread: 37 Java: DefaultDispatcher-worker-1 @coroutine#130 Exception Type: EXC_BAD_ACCESS (SIGABRT) Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000008 Exception Note: EXC_CORPSE_NOTIFY VM Regions Near 0x8:

__TEXT 00000001041fe000-00000001041ff000 [ 4K] r-x/rwx SM=COW /Library/Java/JavaVirtualMachines/jdk-14.0.1.jdk/Contents/Home/bin/java

Application Specific Information: Assertion failed: (!err), function initializeBlioRingBuffers, file /Users/phil/Work/portaudio/pav19/build/macosx/MacPA/MacPA/../../../../src/hostapi/coreaudio/pa_mac_core_blocking.c, line 177.

Here is the code: fun simpleLineInExample(){ val lineIn: LineIn val lineOut: LineOut

        // Create a context for the synthesizer.

        // Create a context for the synthesizer.
        val synth = JSyn.createSynthesizer()
        // Add an audio input.
        synth.add(LineIn().also { lineIn = it })
        // Add an audio output.
        synth.add(LineOut().also { lineOut = it })
        // Connect the input to the output.
        lineIn.output.connect(0, lineOut.input, 0)
        lineIn.output.connect(1, lineOut.input, 1)

        // Both stereo.

        // Both stereo.
        val numInputChannels = 14 // (I know the soundcard has this many, but I could get it from device info)
        val numOutputChannels = 2
        synth.stop()
        synth.start(
            44100, AudioDeviceManager.USE_DEFAULT_DEVICE, numInputChannels,
            AudioDeviceManager.USE_DEFAULT_DEVICE, numOutputChannels
        )

        // We only need to start the LineOut. It will pull data from the LineIn.
        lineOut.start()
        // Sleep a while.
        try {
            val time = synth.currentTime
            // Sleep for a few seconds.
            synth.sleepUntil(time + 8.0)
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
        // Stop everything.
        synth.stop()
    }`
lukasroberts commented 3 years ago

Upon further reading it looks like the number of inputs is always capped in the DualOscilloscope example.

int numInputChannels = deviceMaxInputs.get(itemIndex); if (numInputChannels > 2) numInputChannels = 2;

Given this, I don't understand how to obtain specific inputs from specific channels?

The example I am thinking of is my soundcard has 14 inputs, but I'm only interested in channels 5 and 6. How is this achieved with this library? Whenever I set the channel indexes to something other then 0, or 1, the library just spits out

java.lang.RuntimeException: Audio Input not configured in start() method. at com.jsyn.engine.SynthesisEngine.getInputBuffer(Unknown Source) at com.jsyn.unitgen.ChannelIn.generate(Unknown Source) at com.jsyn.unitgen.UnitGenerator.pullData(Unknown Source)

Seems like it's not possible?

philburk commented 3 years ago

I need to add some tests or demos for multi-channel input and output.

The JPortaudio libraries on the softsynth.com website are very old and need to be rebuilt with the Mac changes from this:

https://github.com/PortAudio/portaudio/pull/356

The example I am thinking of is my soundcard has 14 inputs, but I'm only interested in channels 5 and 6. How is this achieved with this library?

Generally, the solution is to open 8 channels and then just ignore the lower numbered channels you don't want.

philburk commented 3 years ago

the number of inputs is always capped in the DualOscilloscope

That is just a limitation of the example code. You should be able to use the ChannelIn(5) unit to get the 5th channel and then connect it to a scope.

This seems like a bug in JPortAudio or PortAudio.

@lukasroberts - What is your sound card? How many individual input channels versus SPDIF channels? What happens if you only open 8 input channels?