diff --git a/RogueLibsCore/RogueLibs.cs b/RogueLibsCore/RogueLibs.cs index 62666550..310c2b96 100644 --- a/RogueLibsCore/RogueLibs.cs +++ b/RogueLibsCore/RogueLibs.cs @@ -157,9 +157,23 @@ public static RogueSprite CreateCustomSprite(string name, SpriteScope scope, byt /// The caller does not have the required permission. /// The specified is not supported. /// The caller does not have the required permission. + [Obsolete("Use the overload without the AudioType parameter. RogueLibs v4.0.0 now auto-detects the audio format.")] public static AudioClip CreateCustomAudio(string name, byte[] rawData, AudioType format) + => CreateCustomAudio(name, rawData); + /// + /// Creates a custom from and adds it to the game under the specified . Automatically detects the audio format. + /// Supported audio formats: MP3 (.mp3), WAV (.wav, .wave) and Ogg (.ogg, .spx, .opus, .og_). + /// + /// The name of the clip. + /// The byte array containing a raw audio file. + /// The created . + /// An I/O error occurred while opening the file. + /// The caller does not have the required permission. + /// The audio format could not be identified. + /// The caller does not have the required permission. + public static AudioClip CreateCustomAudio(string name, byte[] rawData) { - AudioClip clip = RogueUtilities.ConvertToAudioClip(rawData, format); + AudioClip clip = RogueUtilities.ConvertToAudioClip(rawData); clip.name = name; if (GameController.gameController?.audioHandler != null) { diff --git a/RogueLibsCore/Utilities/RogueUtilities.cs b/RogueLibsCore/Utilities/RogueUtilities.cs index 96fd7e87..a214eb1f 100644 --- a/RogueLibsCore/Utilities/RogueUtilities.cs +++ b/RogueLibsCore/Utilities/RogueUtilities.cs @@ -133,10 +133,25 @@ public static Sprite ConvertToSprite(string filePath, Rect? region, float ppu = } /// - /// Converts an audio file from the specified into an . Detects the audio format by the file's extension. + /// Converts the specified into an using the specified audio . + /// Supported audio formats: MP3 (.mp3), WAV (.wav, .wave) and Ogg (.ogg, .spx, .opus, .og_). + /// + /// MP3-, WAV- or Ogg-encoded audio data. + /// Format of the audio file. + /// Created . + /// An I/O error occurred while opening the file. + /// The caller does not have the required permission. + /// The specified is not supported. + /// The caller does not have the required permission. + [Obsolete("Use the overload without the AudioType parameter. RogueLibs v4.0.0 now auto-detects the audio format.")] + public static AudioClip ConvertToAudioClip(byte[] rawData, AudioType format) + => ConvertToAudioClip(rawData); + /// + /// Converts an audio file from the specified into an using the specified audio . /// Supported audio formats: MP3 (.mp3), WAV (.wav, .wave) and Ogg (.ogg, .spx, .opus, .og_). /// /// Path to the MP3-, WAV- or Ogg-encoded audio file. + /// Format of the audio file. /// Created . /// is an empty string or contains one or more invalid characters. /// is . @@ -145,34 +160,23 @@ public static Sprite ConvertToSprite(string filePath, Rect? region, float ppu = /// An I/O error occurred while opening the file. /// specifies a directory or the caller does not have the required permission. /// File specified in was not found. - /// is in invalid format or the extension's format is not supported. + /// is in invalid format or the specified is not supported. /// The caller does not have the required permission. - public static AudioClip ConvertToAudioClip(string filePath) - { - string extLow = Path.GetExtension(filePath).ToLowerInvariant(); - AudioType type = extLow == ".mp3" ? AudioType.MPEG - : extLow is ".wav" or ".wave" ? AudioType.WAV - : extLow is ".ogg" or ".ogv" or ".oga" or ".ogx" or ".ogm" or ".spx" or ".opus" ? AudioType.OGGVORBIS - : throw new NotSupportedException($"File is in unknown format {extLow}."); - - return ConvertToAudioClip(filePath, type); - } + [Obsolete("Use the overload without the AudioType parameter. RogueLibs v4.0.0 now auto-detects the audio format.")] + public static AudioClip ConvertToAudioClip(string filePath, AudioType format) + => ConvertToAudioClip(filePath); /// - /// Converts the specified into an using the specified audio . + /// Converts the specified into an . Automatically detects the audio format. /// Supported audio formats: MP3 (.mp3), WAV (.wav, .wave) and Ogg (.ogg, .spx, .opus, .og_). /// /// MP3-, WAV- or Ogg-encoded audio data. - /// Format of the audio file. /// Created . /// An I/O error occurred while opening the file. /// The caller does not have the required permission. - /// The specified is not supported. + /// The audio format could not be identified. /// The caller does not have the required permission. - public static AudioClip ConvertToAudioClip(byte[] rawData, AudioType format) + public static AudioClip ConvertToAudioClip(byte[] rawData) { - if (format is not AudioType.MPEG and not AudioType.WAV and not AudioType.OGGVORBIS) - throw new NotSupportedException($"{format} is not supported. Supported audio formats: {AudioType.MPEG}, {AudioType.WAV} and {AudioType.OGGVORBIS}."); - if (!audioCache.TryGetValue(rawData, out AudioClip? audioClip)) { string name = ".audio-request." + Convert.ToString(new System.Random().Next(), 16).ToLowerInvariant(); @@ -181,7 +185,7 @@ public static AudioClip ConvertToAudioClip(byte[] rawData, AudioType format) try { File.WriteAllBytes(filePath, rawData); - audioClip = ConvertToAudioClip(filePath, format); + audioClip = ConvertToAudioClip(filePath); audioCache.Add(rawData, audioClip); } finally @@ -192,11 +196,10 @@ public static AudioClip ConvertToAudioClip(byte[] rawData, AudioType format) return audioClip; } /// - /// Converts an audio file from the specified into an using the specified audio . + /// Converts an audio file from the specified into an . Automatically detects the audio format. /// Supported audio formats: MP3 (.mp3), WAV (.wav, .wave) and Ogg (.ogg, .spx, .opus, .og_). /// /// Path to the MP3-, WAV- or Ogg-encoded audio file. - /// Format of the audio file. /// Created . /// is an empty string or contains one or more invalid characters. /// is . @@ -205,18 +208,48 @@ public static AudioClip ConvertToAudioClip(byte[] rawData, AudioType format) /// An I/O error occurred while opening the file. /// specifies a directory or the caller does not have the required permission. /// File specified in was not found. - /// is in invalid format or the specified is not supported. + /// The audio format could not be identified. + /// is in invalid format or the audio format could not be identified. /// The caller does not have the required permission. - public static AudioClip ConvertToAudioClip(string filePath, AudioType format) + public static AudioClip ConvertToAudioClip(string filePath) { - if (format is not AudioType.MPEG and not AudioType.WAV and not AudioType.OGGVORBIS) - throw new NotSupportedException($"{format} is not supported. Supported audio formats: {AudioType.MPEG}, {AudioType.WAV} and {AudioType.OGGVORBIS}."); + AudioType format = DetectAudioFormat(filePath); + if (format is AudioType.UNKNOWN) + { + const string supported = $"{nameof(AudioType.MPEG)}, {nameof(AudioType.WAV)} and {nameof(AudioType.OGGVORBIS)}"; + throw new NotSupportedException($"This audio format is not supported. Supported audio formats: {supported}."); + } + UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip("file:///" + filePath, format); request.SendWebRequest(); while (!request.isDone) Thread.Sleep(1); return DownloadHandlerAudioClip.GetContent(request); } + private static AudioType DetectAudioFormat(string filePath) + { + using (FileStream stream = File.OpenRead(filePath)) + { + byte[] buffer = new byte[12]; + _ = stream.Read(buffer, 0, 12); + return DetectAudioFormat(buffer); + } + } + private static AudioType DetectAudioFormat(byte[] rawData) + { + static bool IsMP3(byte[] b) // https://github.com/hemanth/is-mp3 + => b[0] == 73 && b[1] == 68 && b[2] == 51 || b[0] == 255 && (b[1] == 251 || b[1] == 250); + static bool IsOGG(byte[] b) // https://github.com/hemanth/is-ogg + => b[0] == 79 && b[1] == 103 && b[2] == 103 && b[3] == 83; + static bool IsWAV(byte[] b) // https://github.com/hemanth/is-wav + => b[0] == 82 && b[1] == 73 && b[2] == 70 && b[3] == 70 && b[8] == 87 && b[9] == 65 && b[10] == 86 && b[11] == 69; + + if (IsMP3(rawData)) return AudioType.MPEG; + if (IsOGG(rawData)) return AudioType.OGGVORBIS; + if (IsWAV(rawData)) return AudioType.WAV; + return AudioType.UNKNOWN; + } + /// /// Returns the 's implemented by the specified . ///