I've tracked down a crash in a game I've been working on to some code which calls freeEffect (actually one of the specialized variants, but also happens with freeEffect). It appears that freeing an effect that is still attached to an active channel will sometimes (details below) cause the audio thread to crash.
For example, this replacing the meat of the init code in bach.mid with this immediately crashes on my (macOS 15.1.1) simulator, and on device. I'm using SDK + firmware 2.7.0-beta2 but reporting here because I'm pretty sure this is true on 2.6.2 as well.
While debugging, I found that the following things all appear to prevent the crash:
setting useDefaultChannel to true
removing the effect before freeing it
having no audio sources on the channel (eg leaving out the file player above)
adding the player to the channel before the overdrive (!)
I'm not sure if this is an expected consequence of freeing an in-use effect (and maybe could use a line in the documentation if so?), or if this is a bug. Thanks for taking a look!
This seems like expected behavior to me? addEffect doesn't make a copy of the effect data because the lifetime of userdata or effectProc can't be guaranteed. So the lifetime of the effect is left to the user to control.
So if you free the effect while the audio process is still calling into it, a crash would be expected.
This seems like expected behavior to me? addEffect doesn't make a copy of the effect data because the lifetime of userdata or effectProc can't be guaranteed. So the lifetime of the effect is left to the user to control.
That seems plausible to me, but "the effect unregisters itself from any channels when you free it" or "you must keep the userdata and effectProc alive until the last reference to the effect is dropped (which might be from a channel referring to it)" also seem like a possible choices. If this is expected behavior, I think documenting the expectations would be helpful. (Unless I missed them, which is quite possible!)
On the C side I've been expecting you to be aware of object lifespans and make sure you don't free something that the system is using, but over time as things have gotten more complex I've added retain counts to various types so we can pass ownership around. Sound sources now do this, and automatically remove themselves from the sound engine when you call their "free" functions (which are now misnamed, technically, but whatevs). We should do the same with effects. Filing that now! And in the meantime I'll put a note in the docs that effects shouldn't be freed while in use.
Maybe I'll go ahead and add retain counts everywhere, like I should have from the beginning..
wait, no.. on second thought, effects don't need multiple ownership, they're only used in one place. I'll just have it remove the effect from the sound engine before it's freed and that'll have the same, uh, effect.