diff --git a/Util/Audio/OfflineAudioMixer.cs b/Util/Audio/OfflineAudioMixer.cs
index 0fa528b..17ee323 100644
--- a/Util/Audio/OfflineAudioMixer.cs
+++ b/Util/Audio/OfflineAudioMixer.cs
@@ -32,7 +32,10 @@ internal sealed class OfflineAudioMixer : IDisposable
/// Additional gain of effect sounds (registered with ).
private const double EffectVolume = 2.0 / 3.0;
- /// Number of tracked effect voices at which finished ones are removed from the list used by .
+ ///
+ /// Smallest number of tracked effect voices at which finished ones are removed from the list used by .
+ /// After each removal the next threshold is twice the remaining count (at least this value).
+ ///
private const int EffectVoicePruneCount = 1024;
/// Longest wait for a commit before checking for cancellation again, in milliseconds.
@@ -49,6 +52,7 @@ internal sealed class OfflineAudioMixer : IDisposable
// Main thread.
private ConditionalWeakTable _sourceVoices = new();
private readonly List _effectVoices = new();
+ private int _effectVoicePruneAt = EffectVoicePruneCount;
private AudioClipSource? _bgmSource;
private string _bgmKey = "";
private Voice? _bgmVoice;
@@ -193,8 +197,11 @@ internal sealed class OfflineAudioMixer : IDisposable
var voice = _mixer.Play(clipSource, clipName, startTime, volume * ClipVolume * EffectVolume, pitch, loop, now);
if (loop) voice.SetEndTime(endTime, now);
- if (_effectVoices.Count >= EffectVoicePruneCount)
+ if (_effectVoices.Count >= _effectVoicePruneAt)
+ {
_effectVoices.RemoveAll(v => v.IsFinished);
+ _effectVoicePruneAt = Math.Max(EffectVoicePruneCount, _effectVoices.Count * 2);
+ }
_effectVoices.Add(voice);
if (source) MapSource(source!, voice);