There seems to be memory leaking when repeatedly creating and disposing the audio player.
I have stripped down a patch we have been using on a project. After hours of running the sound playback always broke at some point producing just crackling noises. Now investigating this issue i see memory leaking when the patch is running.
For each sound to play there is an audio player object with audio out created. When the playback ends this object is disposed.
Is there any flaw with the patch structure / logic itself or Vaudio?
I have tried with Asio4All drivers as well as Asio drivers provided by external USB Soundcard.
I am using gamma 2021.3.3 and the current VL.Audio nuget
EDIT: btw, you do not need to wait hours :P The demo patch breaks quite fast and the leak can be observed in realtime watching taskmanager.
Also it seems after some while, when GC runs peridically the time output on the audio engine stops for a brief moment:
I changed the test patch a litte to make it easier to control the speed/frequency new particles are added. This way you can run it for some time with a high spread count and then lower it again to see if the wavs are still playing correctly. With 300 something playing at once it’s hard to tell.
I moved the AudioOut from the particle into the root patch to make sure it being in the particle doesn’t cause the issue. The particle dispose function didn’t really dispose of anything so I removed it.
yes, looks like there is the dispose missing in the player.
this is a bit tricky to spot, but any process node that has a Dispose will assign it onto the Dispose of the containing patch. so for example the AudioOut. if there is none, an invisible dispose will be introduced, but if you want to call it explicitly, like in the original patch, you have to add it to call it, even if it looks like nothing is assigned to it.
So to report back on testing, my outcome with the altered patch is different than yours :( I still see memory rising like ~300 MB in 15 min. At that time the audio engine already stops every few sec when memory is freed (it is audible and also can be seen at the time pin). When i switch the spawn rate to low i can already hear first cracks form time to time (the cracking is gradual and gets worse with time). Please note this is yet a completely other machine i am running this on.
Tried my patch again and indeed after hammering it for 10 min the memory usage did increase, then decreased the AudioEngine pausing shortly, like @tgd said. When switching to a lower spawn frequency the playback seemed fine though, maybe I wasn’t patient enough (again).
I gave it another go, making the AudioPlayer a class instead of a process node, getting rid of all cache regions inside and removing some other bits that seemed to be “unnecessary” for the usecase.
While running the updated patch for 15 min the memory didn’t increase. But playback seemed to be somewhat broken afterwards, no crackling but something else, hard to describe.
The part that seems to make the difference (but don’t know for sure & haven’t got the time to dig deeper):
maybe I should have phrased it differently, if you want the Dispose method in the node browser category of your type, you have to add it. the type itself will have it as soon as there is any process node that needs Dispose. so you can also use TryDispose without adding the Dispose explicitly to the type.
So you can think of it like a trickle up that you get for free. if you have 10 levels of nested process nodes, if the innermost has a Dispose, all enclosing ones will get one implicitely, so that the application main patch can dispose on exit.
but if you somehow break the cascade by using a class or record that you create, update and dispose dynamiclly/explicitely (for example particles in a soread), then you have to take care of disposing when the instance isnt needed anymore.
Actually it seems fine to me. After 30 min the memory seems stable too. I need to check more when i am in office tomorrow. thanks so far for taking the time to investigate this.
What i wonder about in your patch is the channel output. When i play one instance at a time (lfo at 6 sec), the sound plays on the left channel. since the file is mono, this makes sense. Strange thing is when playing two instnaces (lfo at 4 sec), the second one is coming from the right channel. It also seems not to finish playback but I cant really tell on my laptop, need to check this too on the big soundcard with more channels.
So this part actually is the fix for the memory leak and the crackling. I have modified our original patch just by adding this. Additionally i set the cache region containing OpenFile to Dispose Cached Outputs too but did not test back without. Guess it does not hurt.
So after running 15 hours overnight the playback is still fine and memory stable. Thank you @bjoern!
Turns out this is bad for “normal” playback. A plain audio player node will just run once and break, e.g. when you change the soundfile, it wont play again.
It seems this setting does not affect the other fix when turned off. At least in my rather short test, memory did not increase. I will run the test patch for the night though and report back when i see issues.