Gondwana Game Engine Development (master) - 2.6.1
Gondwana is a cross-platform 2.5D game and rendering engine written in C#/.NET 8. It provides fine-grained control over rendering, timing, and scene composition, with built-in support for parallax, z-ordering, pixel overhang, collision detection, and particle effects. Gondwana targets desktop and web platforms using SkiaSharp for graphics and pluggable audio backends for desktop and browser targets.
Loading...
Searching...
No Matches
NAudioReaderRegistry.cs
1using NAudio.Vorbis;
2using NAudio.Wave;
3
5
9public static class NAudioReaderRegistry
10{
11 private sealed record Registration(Func<Stream, WaveStream>? StreamFactory, Func<string, WaveStream>? FileFactory);
12
13 private static readonly System.Collections.Concurrent.ConcurrentDictionary<string, Registration> Readers = new(StringComparer.OrdinalIgnoreCase);
14
15 static NAudioReaderRegistry()
16 {
17 Register(".wav", stream => new WaveFileReader(stream));
18 Register(".mp3", stream => new Mp3FileReader(stream));
19 Register(".ogg", stream => new VorbisWaveReader(stream));
20 Register(".oga", stream => new VorbisWaveReader(stream));
21 Register(".mogg", stream => new VorbisWaveReader(stream));
22 RegisterFile(".wma", path => new MediaFoundationReader(path));
23 RegisterFile(".m4a", path => new MediaFoundationReader(path));
24 }
25
33 public static void Register(string extension, Func<Stream, WaveStream> readerFactory)
34 {
35 ArgumentNullException.ThrowIfNull(readerFactory);
36 Readers[NormalizeExtension(extension)] = new Registration(readerFactory, null);
37 }
38
46 public static void RegisterFile(string extension, Func<string, WaveStream> readerFactory)
47 {
48 ArgumentNullException.ThrowIfNull(readerFactory);
49 Readers[NormalizeExtension(extension)] = new Registration(null, readerFactory);
50 }
51
57 public static bool Supports(string fileNameOrExtension) => Readers.ContainsKey(GetExtension(fileNameOrExtension));
58
63 public static IEnumerable<string> SupportedExtensions() => Readers.Keys.OrderBy(ext => ext);
64
65 internal static (WaveStream Reader, string? TemporaryFilePath) Open(byte[] data, string fileNameOrExtension)
66 {
67 var extension = GetExtension(fileNameOrExtension);
68 if (!Readers.TryGetValue(extension, out var registration))
69 throw new NotSupportedException($"Format '{extension}' is not supported by Gondwana.Audio.NAudio.");
70
71 if (registration.StreamFactory is not null)
72 {
73 var stream = new MemoryStream(data, writable: false);
74 try
75 {
76 return (registration.StreamFactory(stream), null);
77 }
78 catch
79 {
80 stream.Dispose();
81 throw;
82 }
83 }
84
85 var tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + extension);
86 try
87 {
88 File.WriteAllBytes(tempPath, data);
89 return (registration.FileFactory!(tempPath), tempPath);
90 }
91 catch
92 {
93 TryDelete(tempPath);
94 throw;
95 }
96 }
97
98 private static string GetExtension(string fileNameOrExtension)
99 {
100 var extension = Path.GetExtension(fileNameOrExtension);
101 if (string.IsNullOrWhiteSpace(extension) &&
102 !fileNameOrExtension.Contains('/') && !fileNameOrExtension.Contains('\\'))
103 extension = fileNameOrExtension;
104
105 return NormalizeExtension(extension);
106 }
107
108 private static string NormalizeExtension(string? extension)
109 {
110 if (string.IsNullOrWhiteSpace(extension))
111 throw new InvalidOperationException("Audio source has no file extension.");
112
113 return extension.StartsWith('.') ? extension.ToLowerInvariant() : "." + extension.ToLowerInvariant();
114 }
115
116 internal static void TryDelete(string? path)
117 {
118 if (string.IsNullOrWhiteSpace(path))
119 return;
120
121 try
122 {
123 if (File.Exists(path))
124 File.Delete(path);
125 }
126 catch
127 {
128 // Cleanup is best effort; playback disposal must not mask the original operation.
129 }
130 }
131}