Files
2026-07-13 13:13:17 +08:00

82 lines
3.0 KiB
C#

#nullable enable
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using T3.Core.Audio;
using T3.Core.Resource.Assets;
namespace T3.Editor.Gui.Audio;
internal static class AudioImageFactory
{
internal static bool TryGetOrCreateImagePathForClip(AudioClipResourceHandle handle, [NotNullWhen(true)] out string? imagePath)
{
var audioClip = handle.Clip;
imagePath = null;
ArgumentNullException.ThrowIfNull(audioClip);
if (string.IsNullOrEmpty(audioClip.AssetPath) || handle.LoadingAttemptFailed)
return false;
if (_loadingClips.ContainsKey(audioClip.AssetPath))
{
imagePath = null;
return false;
}
// Return from cache
if (_imageForAudioFiles.TryGetValue(audioClip.AssetPath, out imagePath))
{
return true;
}
// Generate image, if file exists.
if (!AssetRegistry.TryResolveAddress(handle.Clip.AssetPath, handle.Owner, out _, out _))
{
return false;
}
_loadingClips.TryAdd(audioClip.AssetPath, true);
Task.Run(() =>
{
try
{
Log.Debug($"Creating sound image for {audioClip.AssetPath}");
if (AudioImageGenerator.TryGenerateSoundSpectrumAndVolume(audioClip, handle.Owner, out var imagePath))
{
_imageForAudioFiles[audioClip.AssetPath] = imagePath;
}
else
{
Log.Error($"Failed to create sound image for {audioClip.AssetPath}", handle.Owner);
_imageForAudioFiles.TryRemove(audioClip.AssetPath, out _);
}
}
catch (Exception e)
{
// Without this, a throw faults the task silently and the AssetPath stays in
// _loadingClips forever — permanently blocking regeneration with no log line.
Log.Error($"Sound image generation threw for {audioClip.AssetPath}: {e}", handle.Owner);
_imageForAudioFiles.TryRemove(audioClip.AssetPath, out _);
}
finally
{
_loadingClips.TryRemove(audioClip.AssetPath, out _);
}
});
return false;
}
public static void ResetImageCache()
{
_imageForAudioFiles.Clear();
}
// TODO: should be a hashset, but there is no ConcurrentHashset -_-
private static readonly ConcurrentDictionary<string, bool> _loadingClips = new();
private static readonly ConcurrentDictionary<string, string> _imageForAudioFiles = new();
}