[Csnd] Csound WASM: web worker rendering

I was trying the Web Worker thread to render a CSD,

csound = await Csound({useWorker: true} );

but the processing seemed to proceed at realtime pace. I was thinking this should run faster than realtime,
is there anything I need to do for that?

All I am doing is passing a CSD and setting the the output to a file. It runs but much slower than I would
expect.

How is this supposed to be done?

I will take a look, I assume you are using csound in a worker which is a webworker as opposed to worker with sharedArrayBuffer,

it’s a sidenote but if you were want to try the full extent of the performance gains from sharedArrayBuffer, it needs a bit of complexity, which is adding these response headers to the website

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

it will work if window.crossOriginIsolated is set to true.

If you are rendering it doesn’t matter much if it’s in a worker or not, since the useWorker is mostly beneficial for realtime-audio
(especially in cases where the main thread is doing some sort of heavy computation and potentially causing buffer underruns in non worker contextes).

This has happened before, that the rendering is slow in a worker, I believe reported by you some months ago, so I think the same thing is at play here. Will report back!

I was following what I saw in the Web IDE, where you use a worker for rendering. I am supposing this is the vanilla worker, because I have not set up shared arrays.

I am not quite sure then what is the best way to render, because if I don’t set the useWorker option, I get the realtime audio output from Web Audio,
which I don’t need or want.

Could you outline how I would go about rendering faster than realtime?

The problem I have is that I cannot call csound.perform() to do it without calling first csound.start(). But as soon as I call csound.start(), realtime audio starts in an Audio Worklet.

How is this done?

yeh the rendering is all automated, calling perform is done in the library.

I have the correct headers in place in web-ide for sharedArrayBuffer to work, and there is where I fixed it in the past, but not in what I call “vanilla worker”, a name I use for MessagePost based communication as opposed to reading from a shared array.

The fact that useWorker: false rendering isn’t working, sounds like a bug. actually after further reading, it seems it’s missing :frowning:
It sounds like you’re doing things correctly and the issue is on the js library side.

So do I need to disable useSAB?

That doesn’t work anyway.

So the rendering performance with a worker thread is pretty abysmal: a sine wave with envelope runs in about 87% realtime,
which is awfully slow. Is it possible to speed it up? I see you mentioned headers but do you have the JS code or whatever
that I need to put on the page?

See the example at

https://vlazzarini.github.io/vanilla/7.Beep/

I made a wasm patch release 6.18.1, I’m curious if that makes the rendering experience better.

Not notable difference, I am afraid. Rendering a sinewave for 10 s uses 8.3s time, which is about what was there before.
This is with useWorker:true

Ok, will take another look. What I did change was faster rendering with useWorker: false, but I will now go over all the worker setups…

can you try again with 6.18.2?

yes, it’s much faster with useWorker:false, however the callback set by

await csound.on("renderEnded", finish);

does not get called and I am hanging on ‘Score finished in csoundPerformKsmps() with 2.’
Can you check that?

Ok, it’s still slow with the useWorker: true, but the “renderEnded” callback gets called correctly

renderEnded not called sounds like a real bug, I’ll look into it

how slow is it with useWorker true. The reason I don’t tune it to the maximum performance, is because I try to periodically do a 0 second setTimeout, which helps to pick-up events coming in.
This is important for stopping or pausing renders, without it, render without end would render forever. I think I rendered 15 sec sinewave in 1-2 seconds. Maybe you are still 1:1 with realtime and render time?

In the latest 6.18.2, I stil get about 80% realtime (e.g. 8secs for a 10secs sine).

Another thing I noticed with the latest code is that the realtime audio seems to be opened by default, even when I don’t request it.
I am getting the mic permission dialog coming up. In 6.18.0, I think that that did not happen (if I just set -odac as an option and nothing else).

ah ffs, yes true, I’ll fix. I was fixing the detection of it, but I forgot that with useWorker: false, there’s an implicit setting of idac. Will fix!

the new issues are fixed in 6.18.3 as for the render time, I did some work there, but I’m not sure if it’s going to be better with useWorker: true, useWorker: false should be fast in all cases at least.

Thanks, I’ll test it and get back to you.

Prof. Victor Lazzarini
Maynooth University
Ireland

Ok, I tested it:

1) With useWorker: false, Csound plays it to dac despite being given a filename as output.

2) With useWorker: true, Csound renders to file and it is much faster now (about 4s for a 60s sinewave).

So even if useWorker: false is faster I can’t tell because it still renders in realtime to dac.

NB: my code runs on page load, so it does not wait for a user action, it is curious that (at least on
Chrome desktop) the synthesis performance runs to dac without the need to get the AudioContext
started by clicking on a button (for instance). Is that expected?

Sometimes the autoplay policy doesn’t kick in. I wouldn’t count on it working in all cases, but I’ve noticed this too that in same cases, the audio can start without any user interaction, only to realize it wasn’t cross platform the case.

Great news, there’s progress. I’ll scout for some implicit -odac configuration in useWorker: false and update!

I can’t see any leftovers of implicit -odac.

  1. With useWorker: false, Csound plays it to dac despite being given a filename as output.

could you verify this, before calling csound.start, check what the value of
await csound.getOutputName()
is, if it’s a filename or -odac. And if it’s -odac, is there a chance there’s -odac in CsOptions or some csound.setOption call somewhere?