diff --git a/MiraAPI/Utilities/Assets/AudioTools.cs b/MiraAPI/Utilities/Assets/AudioTools.cs
new file mode 100644
index 0000000..abb6bc1
--- /dev/null
+++ b/MiraAPI/Utilities/Assets/AudioTools.cs
@@ -0,0 +1,131 @@
+using System;
+using System.IO;
+using System.Reflection;
+using System.Resources;
+using System.Text;
+using UnityEngine;
+
+namespace MiraAPI.Utilities.Assets;
+
+///
+/// A utility class for various audio-related operations.
+///
+public static class AudioTools
+{
+ ///
+ /// Loads and returns an audio clip from a resource path using the specified .
+ ///
+ /// The path to the resource within the .
+ /// The from which to load the resource.
+ /// A object loaded from the specified resource path.
+ /// Attempted to load an Audio file in non WAV format.
+ /// Stream failed to load. Check if the name of your asset was correct.
+ public static AudioClip LoadAudioFromResources(string resourcePath, Assembly assembly)
+ {
+ using var assetStream = assembly.GetManifestResourceStream(resourcePath)
+ ?? throw new MissingManifestResourceException($"Stream failed to load. Check if the asset name is correct: {resourcePath}");
+
+ using var reader = new BinaryReader(assetStream);
+
+ // Read RIFF header
+ if (Encoding.ASCII.GetString(reader.ReadBytes(4)) != "RIFF")
+ {
+ throw new NotSupportedException("Invalid WAV file (missing RIFF header).");
+ }
+
+ reader.ReadInt32(); // File size (ignore)
+
+ if (Encoding.ASCII.GetString(reader.ReadBytes(4)) != "WAVE")
+ {
+ throw new NotSupportedException("Invalid WAV file (missing WAVE header).");
+ }
+
+ // Read chunks
+ int channels = 0, sampleRate = 0, bitsPerSample = 0;
+ byte[]? audioData = null;
+
+ while (reader.BaseStream.Position < reader.BaseStream.Length)
+ {
+ var chunkId = Encoding.ASCII.GetString(reader.ReadBytes(4));
+ var chunkSize = reader.ReadInt32();
+
+ // Format chunk
+ if (chunkId == "fmt ")
+ {
+ int audioFormat = reader.ReadInt16();
+ channels = reader.ReadInt16();
+ sampleRate = reader.ReadInt32();
+ reader.ReadInt32(); // Byte rate (ignore)
+ reader.ReadInt16(); // Block align (ignore)
+ bitsPerSample = reader.ReadInt16();
+
+ if (audioFormat != 1) // Only PCM supported
+ throw new NotSupportedException("Only PCM WAV files are supported.");
+ }
+
+ // Data chunk
+ else if (chunkId == "data")
+ {
+ audioData = reader.ReadBytes(chunkSize);
+ break; // No need to read further
+ }
+ else
+ {
+ reader.BaseStream.Seek(chunkSize, SeekOrigin.Current); // Skip unknown chunks
+ }
+ }
+
+ if (audioData == null)
+ {
+ throw new InvalidOperationException("WAV file does not contain audio data.");
+ }
+
+ if (channels == 0 || sampleRate == 0 || bitsPerSample == 0)
+ {
+ throw new InvalidOperationException("WAV file does not contain valid format information.");
+ }
+
+ // Convert PCM data to float array
+ var samples = ConvertPcmToFloat(audioData, bitsPerSample);
+
+ // Create the AudioClip
+ var audioClip = AudioClip.Create(resourcePath, samples.Length / channels, channels, sampleRate, false);
+ audioClip.SetData(samples, 0);
+
+ return audioClip;
+ }
+
+ // This is somewhat magic to me, I just copied it from elsewhere.
+ private static float[] ConvertPcmToFloat(byte[] pcmData, int bitsPerSample)
+ {
+ var sampleCount = pcmData.Length / (bitsPerSample / 8);
+ var floatData = new float[sampleCount];
+
+ for (var i = 0; i < sampleCount; i++)
+ {
+ var byteIndex = i * (bitsPerSample / 8);
+
+ switch (bitsPerSample)
+ {
+ case 8:
+ floatData[i] = (pcmData[byteIndex] - 128) / 128f; // 8-bit PCM is unsigned
+ break;
+ case 16:
+ floatData[i] = BitConverter.ToInt16(pcmData, byteIndex) / 32768f;
+ break;
+ case 24:
+ var sample24 = pcmData[byteIndex] | (pcmData[byteIndex + 1] << 8) | (pcmData[byteIndex + 2] << 16);
+ if (sample24 > 0x7FFFFF) sample24 -= 0x1000000; // Convert from unsigned to signed
+ floatData[i] = sample24 / 8388608f;
+ break;
+ case 32:
+ floatData[i] = BitConverter.ToInt32(pcmData, byteIndex) / 2147483648f;
+ break;
+ default:
+ throw new NotSupportedException($"Unsupported bit depth: {bitsPerSample}");
+ }
+ }
+
+ return floatData;
+ }
+}
diff --git a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
index 1bb75ae..8dbc521 100644
--- a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
+++ b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
@@ -1,8 +1,4 @@
-using System;
-using System.IO;
using System.Reflection;
-using System.Resources;
-using System.Text;
using UnityEngine;
namespace MiraAPI.Utilities.Assets;
@@ -19,114 +15,14 @@ public class LoadableAudioResourceAsset(string path) : LoadableAsset
/// Loads the asset from embedded resources.
///
/// The asset to load.
- /// Attempted to load an Audio file in non WAV format.
- /// Stream failed to load. Check if the name of your asset was correct.
+ ///
public override AudioClip LoadAsset()
{
- using var assetStream = _assembly.GetManifestResourceStream(path)
- ?? throw new MissingManifestResourceException($"Stream failed to load. Check if the asset name is correct: {path}");
-
- using var reader = new BinaryReader(assetStream);
-
- // Read RIFF header
- if (Encoding.ASCII.GetString(reader.ReadBytes(4)) != "RIFF")
+ if (!LoadedAsset)
{
- throw new NotSupportedException("Invalid WAV file (missing RIFF header).");
+ LoadedAsset = AudioTools.LoadAudioFromResources(path, _assembly);
}
- reader.ReadInt32(); // File size (ignore)
-
- if (Encoding.ASCII.GetString(reader.ReadBytes(4)) != "WAVE")
- {
- throw new NotSupportedException("Invalid WAV file (missing WAVE header).");
- }
-
- // Read chunks
- int channels = 0, sampleRate = 0, bitsPerSample = 0;
- byte[]? audioData = null;
-
- while (reader.BaseStream.Position < reader.BaseStream.Length)
- {
- var chunkId = Encoding.ASCII.GetString(reader.ReadBytes(4));
- var chunkSize = reader.ReadInt32();
-
- // Format chunk
- if (chunkId == "fmt ")
- {
- int audioFormat = reader.ReadInt16();
- channels = reader.ReadInt16();
- sampleRate = reader.ReadInt32();
- reader.ReadInt32(); // Byte rate (ignore)
- reader.ReadInt16(); // Block align (ignore)
- bitsPerSample = reader.ReadInt16();
-
- if (audioFormat != 1) // Only PCM supported
- throw new NotSupportedException("Only PCM WAV files are supported.");
- }
-
- // Data chunk
- else if (chunkId == "data")
- {
- audioData = reader.ReadBytes(chunkSize);
- break; // No need to read further
- }
- else
- {
- reader.BaseStream.Seek(chunkSize, SeekOrigin.Current); // Skip unknown chunks
- }
- }
-
- if (audioData == null)
- {
- throw new InvalidOperationException("WAV file does not contain audio data.");
- }
-
- if (channels == 0 || sampleRate == 0 || bitsPerSample == 0)
- {
- throw new InvalidOperationException("WAV file does not contain valid format information.");
- }
-
- // Convert PCM data to float array
- var samples = ConvertPcmToFloat(audioData, bitsPerSample);
-
- // Create the AudioClip
- var audioClip = AudioClip.Create(path, samples.Length / channels, channels, sampleRate, false);
- audioClip.SetData(samples, 0);
-
- return audioClip;
- }
-
- // This is somewhat magic to me, I just copied it from elsewhere.
- private static float[] ConvertPcmToFloat(byte[] pcmData, int bitsPerSample)
- {
- var sampleCount = pcmData.Length / (bitsPerSample / 8);
- var floatData = new float[sampleCount];
-
- for (var i = 0; i < sampleCount; i++)
- {
- var byteIndex = i * (bitsPerSample / 8);
-
- switch (bitsPerSample)
- {
- case 8:
- floatData[i] = (pcmData[byteIndex] - 128) / 128f; // 8-bit PCM is unsigned
- break;
- case 16:
- floatData[i] = BitConverter.ToInt16(pcmData, byteIndex) / 32768f;
- break;
- case 24:
- var sample24 = pcmData[byteIndex] | (pcmData[byteIndex + 1] << 8) | (pcmData[byteIndex + 2] << 16);
- if (sample24 > 0x7FFFFF) sample24 -= 0x1000000; // Convert from unsigned to signed
- floatData[i] = sample24 / 8388608f;
- break;
- case 32:
- floatData[i] = BitConverter.ToInt32(pcmData, byteIndex) / 2147483648f;
- break;
- default:
- throw new NotSupportedException($"Unsupported bit depth: {bitsPerSample}");
- }
- }
-
- return floatData;
+ return LoadedAsset!;
}
}
diff --git a/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs b/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs
index 85c76ac..80de3b4 100644
--- a/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs
+++ b/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs
@@ -9,36 +9,26 @@ namespace MiraAPI.Utilities.Assets;
///
/// A utility class for loading multiple assets from an .
///
-public class LoadableBundleSubAssetHolder
+/// The name of the assets to pull from.
+/// The that contains the assets.
+public class LoadableBundleSubAssetHolder(string[] names, AssetBundle bundle)
{
- private readonly string[] spriteNames;
- private readonly AssetBundle bundle;
+ private readonly string[] spriteNames = names;
+ private readonly AssetBundle bundle = bundle;
///
/// Gets the sprites contained within the asset.
///
public Sprite[] SubSprites { get; private set; } = [];
- ///
- /// Initializes a new instance of the class.
- ///
- /// The name of the assets to pull from.
- /// The that contains the assets.
- public LoadableBundleSubAssetHolder(string[] names, AssetBundle bundle)
- {
- this.bundle = bundle;
- spriteNames = names;
- }
-
///
/// Initializes a new instance of the class.
///
/// The name of the asset.
/// The that contains the assets.
public LoadableBundleSubAssetHolder(string name, AssetBundle bundle)
+ : this([name], bundle)
{
- this.bundle = bundle;
- spriteNames = [name];
}
///