Emulate AudioSource Playback State For Effect Sounds

This commit is contained in:
copecone committed 2026-10-14 21:55:13 +09:00
1 parent 5136127e39
commit 69d098e04c
3 files changed
+290 -95

No files matched your search

+21 -17
View File
@@ -50,7 +50,7 @@ internal sealed class OfflineAudioMixer : IDisposable
private readonly int _latencySamples;
// Main thread.
private ConditionalWeakTable<AudioSource, Voice> _sourceVoices = new();
private ConditionalWeakTable<AudioSource, SourceState> _sourceStates = new();
private readonly List<Voice> _effectVoices = new();
private int _effectVoicePruneAt = EffectVoicePruneCount;
private AudioClipSource? _bgmSource;
@@ -191,9 +191,9 @@ internal sealed class OfflineAudioMixer : IDisposable
/// <summary>
/// Starts an effect sound at <paramref name="startTime"/>. An <paramref name="endTime"/> of 0 or more makes it loop until then.
/// <paramref name="source"/> (when given) is mapped to the voice for later changes through the AudioSource.
/// <paramref name="source"/> (when given) is mapped to the returned state, which reports and applies later changes through the AudioSource.
/// </summary>
public Voice RegisterSoundEvent(AudioSource? source, string clipName, double startTime, double endTime, float volume, float pitch, double now)
public SourceState RegisterSoundEvent(AudioSource? source, string clipName, double startTime, double endTime, float volume, float pitch, double now)
{
var clipSource = GetOrAddSource(clipName);
var loop = endTime >= 0;
@@ -207,26 +207,30 @@ internal sealed class OfflineAudioMixer : IDisposable
}
_effectVoices.Add(voice);
if (source) MapSource(source!, voice);
return voice;
var state = new SourceState(voice, Math.Max(startTime, now), pitch, loop, loop ? endTime : double.PositiveInfinity,
clipSource?.Duration ?? 0.0, _sampleRate);
if (source) MapSource(source!, state);
return state;
}
/// <summary>Maps <paramref name="source"/> to <paramref name="voice"/> for later changes through the AudioSource (replaces an earlier mapping).</summary>
public void MapSource(AudioSource source, Voice voice)
/// <summary>
/// Maps <paramref name="source"/> to <paramref name="state"/> (replaces an earlier mapping) and takes the clip length and
/// sample rate from the clip of the source.
/// </summary>
public void MapSource(AudioSource source, SourceState state)
{
_sourceVoices.Remove(source);
_sourceVoices.Add(source, voice);
state.BindClip(source.clip);
_sourceStates.Remove(source);
_sourceStates.Add(source, state);
}
/// <summary>Voice started for <paramref name="source"/> by <see cref="RegisterSoundEvent"/>.</summary>
public bool TryGetVoice(AudioSource? source, out Voice voice)
/// <summary>State of the effect sound last started for <paramref name="source"/>. The mapping stays after the sound ends or stops.</summary>
public bool TryGetSourceState(AudioSource? source, out SourceState state)
{
voice = null!;
return source != null && _sourceVoices.TryGetValue(source, out voice);
state = null!;
return source != null && _sourceStates.TryGetValue(source, out state);
}
public bool RemoveSourceMapping(AudioSource source) => _sourceVoices.Remove(source);
/// <summary>
/// Stops every effect sound at <paramref name="now"/>, including ones scheduled to start later
/// (AudioManager.StopAllSounds destroys every AudioSource in liveSources, which holds the sources of
@@ -237,7 +241,7 @@ internal sealed class OfflineAudioMixer : IDisposable
foreach (var voice in _effectVoices)
voice.Stop(now);
_effectVoices.Clear();
_sourceVoices = new ConditionalWeakTable<AudioSource, Voice>();
_sourceStates = new ConditionalWeakTable<AudioSource, SourceState>();
}
/// <summary>
@@ -348,7 +352,7 @@ internal sealed class OfflineAudioMixer : IDisposable
foreach (var filter in _filters)
filter.Reset();
}
_sourceVoices = new ConditionalWeakTable<AudioSource, Voice>();
_sourceStates = new ConditionalWeakTable<AudioSource, SourceState>();
_effectVoices.Clear();
}
}