using System.Collections.Concurrent; using System.Collections.Generic; using DatReaderWriter; using DatReaderWriter.DBObjs; namespace AcDream.Core.Audio; /// /// DatCollection-backed cache of decoded waves + SoundTable lookups. /// /// /// Lazy-loads each Wave / SoundTable on first request, decodes Wave PCM /// data via , and memoizes the result. Safe to /// call from any thread — the inner dicts are /// . /// /// /// /// Returns null for waves whose format tag isn't PCM (MP3 / ADPCM /// fall through silently until a compressed-decoder path is wired up). /// /// public sealed class DatSoundCache { private readonly DatCollection _dats; private readonly ConcurrentDictionary _waves = new(); private readonly ConcurrentDictionary _tables = new(); public DatSoundCache(DatCollection dats) { _dats = dats; } /// /// Retrieve decoded PCM data for a Wave dat id. Returns null if the /// wave is missing, malformed, or uses a currently-unsupported format /// (MP3 / ADPCM). /// public WaveData? GetWave(uint waveId) { if (_waves.TryGetValue(waveId, out var cached)) return cached; var wave = _dats.Get(waveId); if (wave is null) { _waves[waveId] = null; return null; } var decoded = WaveDecoder.Decode(wave.Header, wave.Data); _waves[waveId] = decoded; return decoded; } /// /// Retrieve a SoundTable by dat id. Returns null if the table is /// missing from the dats. /// public SoundTable? GetSoundTable(uint soundTableId) { if (_tables.TryGetValue(soundTableId, out var cached)) return cached; var table = _dats.Get(soundTableId); _tables[soundTableId] = table; return table; } /// /// Total number of waves that have been accessed (hit or miss). /// Useful for diagnostic overlays. /// public int CachedWaveCount => _waves.Count; /// /// Total number of SoundTables that have been accessed. /// public int CachedSoundTableCount => _tables.Count; }