soul-lang / SOUL

The SOUL programming language and API
Other
1.72k stars 95 forks source link

PatchInstance::createNewPlayer throws unhandled exception #23

Closed christoph-hart closed 4 years ago

christoph-hart commented 4 years ago

My first attempty to wrap SOUL into HISE led me to an unhandled exception deep in the SOUL's secret sauce:

Exception thrown at 0x00007FFDCCE69159 in HISE Debug.exe: Microsoft C++ exception: soul::ParseErrorIgnoringMessageHandler::ErrorWasIgnoredException at memory location 0x0000003A66FFA310.
Exception thrown at 0x00007FFDCCE69159 in HISE Debug.exe: Microsoft C++ exception: soul::ParseErrorIgnoringMessageHandler::ErrorWasIgnoredException at memory location 0x0000003A66FF9FF0.
Exception thrown at 0x00007FFDCCE69159 in HISE Debug.exe: Microsoft C++ exception: soul::AbortCompilationException at memory location 0x0000003A66FFCB18.

It happens when I called PatchInstance::createNewPlayer() with the Reverb example patch. The Delay loads just fine.

I am sure I did some mistake during wrapping the code anywhere, but shouln't the most top level compile call catch any parsing errors and convert it into a debug message?

julianstorer commented 4 years ago

Those are internal exceptions that are used to handle some tricky parsing situations, and are completely normal and expected. Are you sure they're unhandled?

christoph-hart commented 4 years ago

Well, it ends up in the catch-all branch of the thread's run method, so yeah, it's not handled inside the function call.

Note that I am not using the SoulAudioPluginInstance / SoulAudioProcessor helper classes but call the function PatchInstance::createNewPlayer() directly from my code.

BTW, is there any runtime debugging functionality in SOUL yet? I've subclassed soul::patch::DebugMessageHandler to print to the HISE console and it works perfectly for compilation errors, but it would be awesome to be able to call something like DBG(audioIn); from within SOUL to inspect the algorithms.

cesaref commented 4 years ago

We're adding support for a debug stream (called console) which you can write to from any processor and it'll come through on that callback. I don't think it's in the current release, but will be in the next.

julianstorer commented 4 years ago

I was just looking at this, but it seems impossible that the exception could escape.. That exception is only thrown when a ParseErrorIgnoringMessageHandler object is active, and the only two places in the code which use the class are both are wrapped in a catch... (??) Can you maybe share some code that triggers it?

christoph-hart commented 4 years ago

Yeah sure, here's the glue code I wrote to embed SOUL (it's extremely hacky, as I just wanted to get this to work as quickly as possible to evaluate the next steps):

https://github.com/christophhart/HISE/blob/scriptnode/hi_scripting/scripting/scriptnode/soul/custom/SoulNode.cpp

I am creating the patch player on line 107, there it throws the exception, but only with the Reverb example - the Delay, Diode and PadSynth examples will compile just fine).

BTW: If I am calling this method multiple times in a row (up to 256 times) in order to create an array of PatchPlayers, is it recompiling it each time or just cloning the compiled object? Because this would be my approach for polyphony - each voice is its dedicated patch player and the voice management system is still handled from the outside so I can use all the other tools available in HISE.

julianstorer commented 4 years ago

Well, this is a mystery - when I load the reverb patch, it certainly throws that exception internally but it's caught as intended. And I just can't see any possible way it could happen otherwise. All the other patches also throw it internally too - maybe put a breakpoint on the actual throw statement (there's only one place it happens) and see what the difference is in the stack?

Are you 100% sure it's not just that you're seeing the console log about this exception, and then some other later exception is what's actually throwing you into your top-level exception handler?

Or have you got some other thing like "stop on all exceptions" enabled and the debugger is showing you misleading info about what's happening?

christoph-hart commented 4 years ago

I think I found the issue: I was calling this method with an uninitialised PatchPlayerConfiguration object (samplerate was zero). If I defer the compilation until I know the playback specs, it goes through.

So it was probably a divide by zero exception :)

julianstorer commented 4 years ago

Was it a divide by zero in our code? If so let me know where, as I'd like to make sure that can't happen!

christoph-hart commented 4 years ago

All I can say is that passing in a PatchPlayerConfiguration with a zero samplerate into function call compileNewPlayer throws an uncatched Exception somewhere in the DLL code. Have you explicitely handled this case? I would assume that it doesn't start the compilation altogether.

julianstorer commented 4 years ago

OK, thanks - yep, I think what you were seeing was an unhandled assertion triggered by the zero sample rate. I'll sort that out so that it gives a proper error message instead!