// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System; using System.IO; using System.Threading; using System.Threading.Tasks; using UltimateXR.Exceptions; using UltimateXR.Extensions.System; using UltimateXR.Extensions.System.IO; using UltimateXR.Extensions.Unity.IO; using UnityEngine; namespace UltimateXR.Extensions.Unity.Audio { /// /// Audio extensions. /// public static partial class AudioClipExt { #region Public Methods /// /// Ubiquitously plays an . /// /// /// This function creates an but automatically disposes of it once the clip has finished /// playing. /// /// Reference to the sound clip file that will be played. /// How loud the sound is at a distance of one world unit (one meter) [0.0, 1.0]. /// Delay time specified in seconds. /// /// Amount of change in pitch due to slowdown/speed up of the Audio Clip. Value 1 is normal playback speed. /// /// Start offset in seconds /// The just created temporal . /// public static AudioSource PlayClip(AudioClip self, float volume = 1.0f, float delay = 0.0f, float pitch = 1.0f, float offsetSeconds = 0.0f) { return AudioSourceExt.PlayClip(self, volume, delay, pitch, offsetSeconds); } /// /// Plays an AudioClip at a given position in world space. /// /// /// This function creates an but automatically disposes of it once the clip has finished /// playing. /// /// Reference to the sound clip file that will be played. /// Position in world space from which sound originates. /// How loud the sound is at a distance of one world unit (one meter) [0.0, 1.0]. /// Delay time specified in seconds. /// /// Amount of change in pitch due to slowdown/speed up of the Audio Clip. Value 1 is normal playback /// speed. /// /// Sets how much the 3D engine has an effect on the audio source [0.0, 1.0]. /// Start offset in seconds /// The just created temporal . /// public static AudioSource PlayClipAtPoint(AudioClip self, Vector3 point, float volume = 1.0f, float delay = 0.0f, float pitch = 1.0f, float spatialBlend = AudioSourceExt.SpatialBlend3D, float offsetSeconds = 0.0f) { return AudioSourceExt.PlayClipAtPoint(self, point, volume, delay, pitch, spatialBlend, offsetSeconds); } /// /// Asynchronous and ubiquitously plays the . /// /// /// This function creates an but automatically disposes of it once the clip has finished /// playing. /// /// Reference to the sound clip file that will be played. /// How loud the sound is at a distance of one world unit (one meter) [0.0, 1.0]. /// Delay time specified in seconds. /// /// Amount of change in pitch due to slowdown/speed up of the Audio Clip. Value 1 is normal playback /// speed. /// /// Start offset in seconds /// to stop playing. /// An awaitable . /// public static Task PlayAsync(this AudioClip self, float volume = 1.0f, float delay = 0.0f, float pitch = 1.0f, float offsetSeconds = 0.0f, CancellationToken ct = default) { return AudioSourceExt.PlayClipAsync(self, volume, delay, pitch, offsetSeconds, ct); } /// /// Asynchronously plays the at a given position in world space. /// /// /// This function creates an but automatically disposes of it once the clip has finished /// playing. /// /// Reference to the sound clip file that will be played. /// Position in world space from which sound originates. /// How loud the sound is at a distance of one world unit (one meter) [0.0, 1.0]. /// Delay time specified in seconds. /// /// Amount of change in pitch due to slowdown/speed up of the Audio Clip. Value 1 is normal playback /// speed. /// /// Sets how much the 3D engine has an effect on the audio source [0.0, 1.0]. /// Start offset in seconds /// to stop playing. /// An awaitable . /// public static Task PlayAtPointAsync(this AudioClip self, Vector3 point, float volume = 1.0f, float delay = 0.0f, float pitch = 1.0f, float spatialBlend = AudioSourceExt.SpatialBlend3D, float offsetSeconds = 0.0f, CancellationToken ct = default) { return AudioSourceExt.PlayClipAtPointAsync(self, point, volume, delay, pitch, spatialBlend, offsetSeconds, ct); } /// /// Creates an from a PCM stream. /// /// The source stream /// The name assigned to the clip /// The object public static AudioClip FromPcmStream(Stream sourceStream, string clipName = "pcm") { clipName.ThrowIfNullOrWhitespace(nameof(clipName)); byte[] bytes = new byte[sourceStream.Length]; sourceStream.Read(bytes, 0, bytes.Length); return FromPcmBytes(bytes, clipName); } /// /// Creates an from a PCM stream asynchronously. /// /// The source stream /// The name assigned to the clip /// The optional cancellation token, to cancel the task /// An awaitable task that returns the object public static async Task FromPcmStreamAsync(Stream sourceStream, string clipName = "pcm", CancellationToken ct = default) { clipName.ThrowIfNullOrWhitespace(nameof(clipName)); byte[] bytes = new byte[sourceStream.Length]; await sourceStream.ReadAsync(bytes, 0, bytes.Length, ct); return await FromPcmBytesAsync(bytes, clipName, ct); } /// /// Creates an from a PCM byte array. /// /// The source data /// The name assigned to the clip /// The object public static AudioClip FromPcmBytes(byte[] bytes, string clipName = "pcm") { clipName.ThrowIfNullOrWhitespace(nameof(clipName)); var pcmData = PcmData.FromBytes(bytes); var audioClip = AudioClip.Create(clipName, pcmData.Length, pcmData.Channels, pcmData.SampleRate, false); audioClip.SetData(pcmData.Value, 0); return audioClip; } /// /// Creates an from a PCM byte array asynchronously. /// /// The source data /// The name assigned to the clip /// The optional cancellation token, to cancel the task /// An awaitable task that returns the object public static async Task FromPcmBytesAsync(byte[] bytes, string clipName = "pcm", CancellationToken ct = default) { clipName.ThrowIfNullOrWhitespace(nameof(clipName)); var pcmData = await Task.Run(() => PcmData.FromBytes(bytes), ct); var audioClip = AudioClip.Create(clipName, pcmData.Length, pcmData.Channels, pcmData.SampleRate, false); audioClip.SetData(pcmData.Value, 0); return audioClip; } /// /// Asynchronously reads and loads an into memory from a given /// /// Full path for file /// The optional cancellation token, to cancel the task /// Loaded /// /// HttpError flag is on /// /// /// NetworkError flag is on /// /// /// The task was canceled using /// public static Task FromFile(string uri, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); uri.ThrowIfNullOrWhitespace(nameof(uri)); try { return UnityWebRequestExt.LoadAudioClipAsync(uri, ct); } catch (UwrException e) { throw new FileNotFoundException(e.Message, uri, e); } } /// /// Asynchronously reads and loads an into memory from a given /// pointing to a file with PCM bytes. /// /// Full path with the PCM bytes /// Optional cancellation token to cancel the task /// Loaded /// /// HttpError flag is on /// /// /// NetworkError flag is on /// /// /// The task was canceled using /// public static async Task FromPcmFile(string uri, CancellationToken ct = default) { string fileName = Path.GetFileNameWithoutExtension(uri); byte[] bytes = await FileExt.Read(uri, ct); return await FromPcmBytesAsync(bytes, fileName, ct); } /// /// Creates a object from a stream containing PCM data. /// /// PCM data /// The name that will be assigned to the clip /// object public static StreamedPcmClip CreatePcmStreamed(Stream pcmStream, string clipName = "pcm") { return StreamedPcmClip.Create(pcmStream, clipName); } #endregion } }